Skip to content
Go
crypto/tls — 安全传输层

crypto/tls — 安全传输层

crypto/tlsnet 的接口之上实现了 TLS 协议,使得 TCP 连接可以被透明地加密和认证。


1. TLS 基础概念速览

概念 作用
证书 (Certificate) 证明服务器/客户端身份
私钥 (Private Key) 解密/签名,绝不可外泄
CA 证书 签名其他证书的信任锚点
TLS 握手 协商加密套件、交换密钥
mTLS 双向 TLS:服务端也验证客户端证书

2. TLS 服务器

2.1 基础 HTTPS 服务器

server := &http.Server{
    Addr: ":8443",
}

// 方式 1:直接指定证书文件
log.Fatal(server.ListenAndServeTLS("server.crt", "server.key"))

// 方式 2:通过 TLSConfig 配置更多选项
tlsConfig := &tls.Config{
    MinVersion: tls.VersionTLS12,
    MaxVersion: tls.VersionTLS13,
    // 密码套件(仅 TLS 1.2 及以下需要)
    CipherSuites: []uint16{
        tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
        tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
    },
    PreferServerCipherSuites: true,
}

server.TLSConfig = tlsConfig
log.Fatal(server.ListenAndServeTLS("server.crt", "server.key"))

💡 最佳实践

  • 生产环境最低使用 TLS 1.2,推荐 TLS 1.3
  • TLS 1.3 的密码套件由协议自动协商,不需要手动配置 CipherSuites
  • 证书建议使用 Let’s Encrypt 自动管理(golang.org/x/crypto/acme/autocert)。

2.2 开发环境自签名证书

func generateSelfSignedCert() (tls.Certificate, error) {
    privKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        return tls.Certificate{}, err
    }

    template := &x509.Certificate{
        SerialNumber: big.NewInt(1),
        Subject:      pkix.Name{CommonName: "localhost"},
        NotBefore:    time.Now(),
        NotAfter:     time.Now().Add(365 * 24 * time.Hour),
        KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
        ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
        DNSNames:     []string{"localhost", "127.0.0.1"},
    }

    derBytes, err := x509.CreateCertificate(rand.Reader, template, template,
        &privKey.PublicKey, privKey)
    if err != nil {
        return tls.Certificate{}, err
    }

    return tls.Certificate{
        Certificate: [][]byte{derBytes},
        PrivateKey:  privKey,
    }, nil
}

3. TLS 客户端

3.1 基础 HTTPS 客户端

client := &http.Client{
    Transport: &http.Transport{
        TLSClientConfig: &tls.Config{
            MinVersion: tls.VersionTLS12,
        },
    },
}
resp, _ := client.Get("https://example.com")

🚨 陷阱InsecureSkipVerify: true 跳过证书验证,仅用于开发环境。在生产中这样做等于没有 TLS。

3.2 使用自定义 CA 证书

// 加载自定义 CA 证书
caCert, err := os.ReadFile("ca.crt")
if err != nil {
    log.Fatal(err)
}

caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

tlsConfig := &tls.Config{
    RootCAs:    caCertPool, // 使用自定义 CA
    MinVersion: tls.VersionTLS12,
}

4. mTLS — 双向 TLS

mTLS 要求:服务端验证客户端证书,客户端验证服务端证书。常用于内部微服务间的零信任安全。

4.1 服务端配置

caCert, _ := os.ReadFile("ca.crt")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

serverCert, _ := tls.LoadX509KeyPair("server.crt", "server.key")

tlsConfig := &tls.Config{
    Certificates: []tls.Certificate{serverCert},
    ClientAuth:   tls.RequireAndVerifyClientCert, // ← 关键
    ClientCAs:    caCertPool,
    MinVersion:   tls.VersionTLS12,
}

server := &http.Server{
    Addr:      ":8443",
    TLSConfig: tlsConfig,
}

4.2 客户端配置

clientCert, _ := tls.LoadX509KeyPair("client.crt", "client.key")

caCert, _ := os.ReadFile("ca.crt")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

tlsConfig := &tls.Config{
    Certificates: []tls.Certificate{clientCert}, // 客户端证书
    RootCAs:      caCertPool,
    MinVersion:   tls.VersionTLS12,
}

client := &http.Client{
    Transport: &http.Transport{TLSClientConfig: tlsConfig},
}

4.3 获取对端证书信息

func handler(w http.ResponseWriter, r *http.Request) {
    if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
        clientCert := r.TLS.PeerCertificates[0]
        fmt.Fprintf(w, "Client CN: %s\n", clientCert.Subject.CommonName)
        fmt.Fprintf(w, "Client DNS: %v\n", clientCert.DNSNames)
    }
}

5. 🔬 TLS 握手流程

Client                          Server
  |                               |
  |--- ClientHello ------------->|
  |   (支持的版本、密码套件、SNI)|
  |                               |
  |<-- ServerHello --------------|
  |   Certificate                 |
  |   (ServerHelloDone)          |
  |                               |
  |--- (ClientCertificate) ----->|  ← mTLS 才有
  |    ClientKeyExchange          |
  |    (CertificateVerify)        |
  |    ChangeCipherSpec           |
  |    Finished                   |
  |                               |
  |<-- ChangeCipherSpec ---------|
  |    Finished                   |
  |                               |
  |<===== 加密通信 =============>|

🔬 TLS 1.3 优化:握手减少到 1-RTT(往返一次),且大部分加密套件是 AEAD(GCM/ChaCha20-Poly1305)。


6. 🚨 TLS 常见陷阱

陷阱 影响 解决
InsecureSkipVerify: true 中间人攻击 仅开发环境使用
TLS 1.0/1.1 已知漏洞 设置 MinVersion: tls.VersionTLS12
证书过期无人监控 服务不可用 使用 autocert 或监控
HTTP/2 降级 TLS 1.2 下需要 ALPN 设置 NextProtos: []string{"h2", "http/1.1"}
crypto/rsa 1024 位密钥 已可破解 使用 RSA 2048+ 或 ECDSA P-256

💡 最佳实践:使用 golang.org/x/crypto/acme/autocert 自动从 Let’s Encrypt 获取和续期证书。