2. TLS/SSL 基础:协议工作原理与证书链

2.1 TLS 握手:怎么建立安全连接

TLS 握手,说白了就是客户端和服务器在正式传输数据前,先互相打个招呼,商量好用什么加密算法、交换密钥、验证身份。这个过程大概在几十毫秒内完成,但里面细节不少。我早年调试一个 HTTPS 服务时,就碰到过握手卡在 Certificate 阶段,整个页面加载超时,排查了半天才发现是证书链没发全——嗯,这就是我们今天要聊的重点。

一个典型的 TLS 1.2 握手流程如下:

  1. 客户端发送 ClientHello,包含支持的 TLS 版本、密码套件列表、随机数。
  2. 服务端回复 ServerHello,选定版本和密码套件,并带上自己的随机数。
  3. 服务端发送 Certificate 消息,携带服务器证书以及中间证书(证书链)。
  4. 服务端可选发送 ServerKeyExchange(用于密钥协商的参数)。
  5. 服务端发送 ServerHelloDone,表示 Hello 阶段结束。
  6. 客户端验证证书链(关键步骤),然后发送 ClientKeyExchange 传递预主密钥(用服务端公钥加密)。
  7. 双方各自计算会话密钥,发送 ChangeCipherSpec 切换加密,最后 Finished 消息确认握手成功。

你可能会问:TLS 1.3 是不是快很多?没错,1.3 把握手压缩到一次往返,还把不安全的算法全扔了。我习惯用这个表格对比两者的核心差异:

对比项TLS 1.2TLS 1.3
握手往返次数2 次完整 RTT1 次 RTT(初次),0-RTT 可复用
密码套件协商支持多种旧算法(RC4, 3DES)只保留 AEAD 强算法(AES-GCM, ChaCha20)
密钥交换RSA 或 (EC)DHE强制 (EC)DHE,前向安全性
证书链传递明文在 Certificate 消息中加密后传递(除 ServerHello 外)
握手消息数量约 10 条减少到 5 条

我的建议:如果在 KMS 集成场景下做 TLS Termination,优先选 TLS 1.3。一方面减少延迟,另一方面前向安全性对密钥保护更友好。但要注意有些老旧客户端(比如某些银行系统)只支持 1.2,得留个降级通道。

2.2 证书链:信任是如何传递的

证书链,说白了就是一层一层证明你的身份。根 CA 给中间 CA 签发证书,中间 CA 再给你的服务器签发证书。客户端拿到服务器证书后,会顺着这条链往上找,直到找到一个它本身就信任的根 CA 为止。这个“信任锚”通常是操作系统的受信任根证书存储。

我举个例子:你公司买了一台负载均衡器做 TLS Termination,运维配置了一个证书,结果手机访问提示“证书无效”。查了半天发现,他们只上传了服务器证书,没把中间 CA 证书带上。客户端自然找不到通往根 CA 的路径——这就是典型的“证书链不完整”!

证书链验证的完整过程:

  • 检查服务器证书的签名是否由上级 CA 签发(用上级公钥解密签名,比对证书摘要)。
  • 逐级向上检查每个中间 CA 证书的签名,直到根 CA。
  • 检查根 CA 是否在客户端信任存储中。
  • 检查每个证书的有效期、吊销状态(CRL/OCSP)、密钥用法等扩展域。

下面这张图直观展示了证书链的层级结构和验证方向:

证书链信任结构 根CA (Root CA) 中间CA1 中间CA2 服务器证书 客户端验证 验证方向 从服务器证书开始, 逐级向上直到根CA 签发关系 上级CA签发下级证书 (自上而下)

我曾经踩过的坑:有一次线上 KMS 网关做 TLS Termination,配置了完整的证书链,结果某个内部客户端死活连不上,报“certificate chain too long”。查才发现中间 CA 链深度超过了 4 级,而那个旧系统的 SSL 库限制链深度为 3。自那以后,我习惯把中间 CA 控制在 2 级以内,最多 3 级。

2.3 证书链验证实战要点

你如果在终端里想验证证书链是否完整,可以用 openssl 来模拟客户端验证:

# 查看服务器证书 + 中间链(假设已下载到本地)
openssl verify -CAfile <根CA证书> -untrusted <中间链文件> server.crt

# 或者直接连接测试
openssl s_client -connect example.com:443 -showcerts

s_client 的输出会打印整个证书链,你可以一眼看出中间证书是否都发过来了。如果只有服务器证书,没有中间证书,那客户端大概率会报“unable to get local issuer certificate”。

这里我总结几个证书链的“硬指标”:

检查项要求常见问题
链完整性服务器证书 → 中间CA1 → … → 根CA (客户端信任)漏发中间CA
链深度建议 ≤ 3 级旧设备限制 3 级
签名算法禁用 MD5、SHA-1(仅限 2016 年前签发)旧系统使用 SHA-1 根
有效期所有证书均在有效期内根CA过期但未更新信任库
密钥长度RSA ≥ 2048 位;ECC ≥ 256 位旧证书用 1024 位已被弃用

我个人习惯在 TLS Termination 设备上额外开启 OCSP Stapling,让服务端主动提供证书的吊销状态,避免客户端每次都去 OCSP 服务器查询,既减少延迟又保护隐私。但注意中间 CA 也要支持 Stapling,否则会降级。