TLS 握手基本流程:Cipher Suite 协商、证书交换、密钥交换详解

TLS 握手,说白了就是客户端和服务器在正式开始加密通信前,先互相确认身份、商量加密算法、生成共享密钥的过程。我处理过上百次握手失败的案例,每次排查的第一步,就是搞清楚握手卡在了哪个阶段。

整个握手可以拆成三个核心环节:Cipher Suite 协商、证书交换与验证、密钥交换与派生。下面我逐一展开,里面会穿插一些实战中踩过的坑。

TLS 1.2 握手核心流程 客户端 (Client) 服务器 (Server) ① ClientHello ② ServerHello + Certificate ③ ServerKeyExchange (可选) ④ ClientKeyExchange ⑤ ChangeCipherSpec ⑥ Finished 三阶段对应 ①-②:Cipher Suite 协商 ②-③:证书交换与验证 ③-④:密钥交换 ⑤-⑥:握手完成确认

1. Cipher Suite 协商——谁来决定加密方案?

握手的第一步,客户端会发一个 ClientHello 消息,里面带一个长长的列表——支持的密码套件(Cipher Suite)。说白了,就是客户端告诉服务器:“我会的这些加密算法组合,你挑一个咱俩都能用的。”

服务器收到后,从列表里选一个自己支持的,通过 ServerHello 回复。如果服务器的密码套件列表和客户端完全没有交集……嗯,握手直接就断了。我曾经在一个项目中,客户端的 OpenSSL 版本太老,只支持 RC4 和 3DES,而服务器已经禁用了所有弱算法,双方僵在那儿,日志里就显示 no shared cipher。

实用建议:排查密码套件不匹配时,我最先做的事就是抓包看 ClientHello 和 ServerHello 的 Cipher Suite 字段。用 Wireshark 的过滤表达式 tls.handshake.type == 2 就能快速定位。

一个典型的密码套件名称长这样:

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|    |       |    |        |       |
|    密钥交换 认证  对称加密  模式   哈希

我习惯把 Cipher Suite 的四个要素记在脑子里:密钥交换算法、认证算法、对称加密算法、MAC/PRF 算法。缺一不可。

2. 证书交换与验证——你真是你吗?

协商完密码套件后,服务器会发来它的证书链(Certificate 消息)。客户端拿到证书后要做三件事:

  • 验证签名:用 CA 的公钥验签,确保证书未被篡改。
  • 检查有效期:当前时间必须在证书的 valid_from 和 valid_to 之间。我见过很多因为服务器系统时间不准导致证书过期误报的案例。
  • 检查域名:证书中的 Common Name (CN) 或 Subject Alternative Name (SAN) 必须匹配客户端请求的域名。
避坑提醒:我曾经遇到一个诡异问题:证书链不完整。服务器只发了终端证书,没发中间 CA 证书。客户端(特别是移动端)没有预置那个中间 CA,直接报 certificate unknown。解决方法很简单——让服务器配置完整的证书链。

如果验证全部通过,客户端会生成一个 pre-master secret(预主密钥),然后用服务器的公钥加密后发送回去——这就进入了第三阶段。

3. 密钥交换——安全地共享秘密

密钥交换的方式取决于之前协商的 Cipher Suite。我主要讲两种常见场景:

密钥交换算法 核心原理 常见场景
RSA 密钥交换 客户端生成 pre-master secret,用服务器 RSA 公钥加密后发送 老旧系统,TLS 1.2 及以前
(EC)DHE 密钥交换 双方各自生成临时 DH 参数,交换公钥,各自计算共享密钥 现代实践(提供前向安全性)

如果是 ECDHE,服务器会先发 ServerKeyExchange 消息,带上椭圆曲线参数和签名。客户端验证签名后,生成自己的临时密钥对,通过 ClientKeyExchange 把公钥发过去。最后双方各自计算出相同的 pre-master secret。

我的经验:ECDHE 虽然安全,但在高并发场景下,椭圆曲线运算可能成为瓶颈。我优化过一个 HTTPS 网关,把椭圆曲线从 P-256 切换到 X25519,CPU 占用率下降了约 30%。当然前提是客户端也支持。

一旦 pre-master secret 生成完毕,双方会用它派生出对称加密的会话密钥(master secret -> key material)。然后各自发送 ChangeCipherSpec 和 Finished 消息,验证握手完整性。至此,TLS 握手完成,后续数据全部加密传输。

小结一下

三个环节缺一不可:密码套件协商决定了算法;证书交换建立了信任;密钥交换生成了会话密钥。你想想看,任何一个环节出问题,握手都会失败。我在排障时,总是先从 Wireshark 的握手流程图入手,看具体卡在哪个 message 上,然后对照这三个阶段定位根因。

快速检查清单:
  • ClientHello 中的 Cipher Suites 列表是否完整?
  • ServerHello 中是否返回了有效的 Cipher Suite?
  • Certificate 消息中的证书链是否完整且可验证?
  • ClientKeyExchange 消息是否被成功解密?
  • Finished 消息中的 verify_data 是否匹配?