2. TLS握手全流程拆解
TLS 握手的本质,是在客户端与服务器之间用若干次往返,协商出一组双方都认可的密码套件、验证服务器身份,并最终派生出用于对称加密的应用流量密钥。理解握手,不能只记“四次握手”这个结论,而要看清每个报文携带什么、谁在等待谁、哪些步骤消耗往返时间(RTT)、哪些步骤消耗计算时间。本节以 TLS 1.2 完整握手为主线,穿插 TLS 1.3 的差异,并给出会话恢复的机制与延迟账本。
一、完整握手的报文序列与职责
一次典型的 TLS 1.2 完整握手(以 ECDHE_RSA 密钥交换为例)包含以下报文:
- ClientHello:客户端发送支持的 TLS 版本、密码套件列表、随机数
client_random、扩展(SNI、ALPN、支持的椭圆曲线、签名算法等)。 - ServerHello:服务器选定版本与密码套件,返回
server_random与选定扩展。 - Certificate:服务器发送证书链,通常为叶证书 + 中间 CA,客户端据此验证身份。
- ServerKeyExchange:ECDHE 场景下携带服务器临时公钥、所选曲线与签名,签名覆盖客户端与服务器随机数,防止篡改。
- ServerHelloDone:服务器宣告本轮发言结束,等待客户端响应。
- ClientKeyExchange:客户端生成自己的 ECDHE 临时公钥并发送。
- ChangeCipherSpec + Finished:客户端切换为加密状态,发送用握手密钥保护的 Finished,其内容是之前所有握手报文的摘要,用于校验握手完整性。
- 服务器 ChangeCipherSpec + Finished:服务器同样切换并回送 Finished,握手完成,随后进入应用数据传输。
从延迟角度看,TLS 1.2 完整握手需要 2 个 RTT 才能开始发送应用数据:第一个 RTT 完成 ClientHello/ServerHello 及证书交换,第二个 RTT 完成密钥交换与 Finished 校验。若叠加 TCP 三次握手,首次连接的总建立延迟约为 3 个 RTT。
二、密钥交换:ECDHE 为什么成为主流
密钥交换决定了“双方如何在不安全信道上得到相同的会话密钥”。RSA 密钥交换中,客户端用服务器证书公钥加密预主密钥,一旦服务器私钥泄露,历史流量可被解密,不具备前向保密。ECDHE 则让双方各自生成临时密钥对,交换公钥后通过椭圆曲线 Diffie-Hellman 计算出共享秘密,临时私钥用完即弃,因此具备前向保密。
以 secp256r1 曲线为例,客户端与服务器各自生成临时私钥 d 与公钥 Q = d·G,交换 Q 后计算 S = d·Q_peer,双方得到相同的共享点。随后通过 PRF(伪随机函数)将 client_random、server_random 与共享秘密 S 派生出主密钥,再扩展为握手密钥与应用流量密钥。这一过程在 TLS 1.2 中需要两个 RTT 完成,而 TLS 1.3 将密钥交换与 Finished 合并,压缩到 1 个 RTT。
三、证书验证:客户端在验证什么
收到 Certificate 报文后,客户端并非“看一眼就信”,而是执行一条完整的验证链:
- 签名链验证:用中间 CA 公钥验证叶证书签名,再用根 CA 公钥验证中间 CA 签名,直到本地信任库中的根证书。
- 有效期检查:证书的
notBefore与notAfter必须覆盖当前时间。 - 域名匹配:证书 SAN 字段必须包含客户端访问的主机名,通配符只覆盖单层子域。
- 吊销状态:通过 CRL 或 OCSP 检查证书是否被吊销。OCSP 若同步请求,会额外增加一次网络往返,是常见的延迟来源。
- 密钥用途:扩展密钥用途需允许服务器身份验证。
验证失败时,客户端会发送 alert 并终止连接。常见错误包括证书过期、域名不匹配、链不完整、自签名证书未被信任。工程上应确保证书链完整下发中间 CA,并启用 OCSP Stapling,让服务器在握手时直接附带 OCSP 响应,避免客户端额外查询。
四、会话恢复:把 2 RTT 降到 1 RTT 甚至 0 RTT
完整握手成本高,因此 TLS 提供了会话恢复机制。TLS 1.2 有两种方式:
- Session ID:服务器在 ServerHello 中返回 Session ID,客户端后续在 ClientHello 中携带该 ID,服务器若命中缓存则直接进入 ChangeCipherSpec,跳过证书与密钥交换,只需 1 个 RTT。
- Session Ticket:服务器将加密的会话状态作为 Ticket 发给客户端,客户端下次携带 Ticket,服务器解密后恢复会话。它把状态存储在客户端,适合无共享缓存的集群。
TLS 1.3 进一步引入 PSK(预共享密钥)恢复,并支持 0-RTT 早期数据:客户端在第一个飞行中就携带加密的应用数据,但 0-RTT 数据不具备前向保密且可能被重放,只适合幂等请求。会话恢复的代价是牺牲部分前向保密性,且服务器需要维护缓存或票据密钥,需在性能与安全之间权衡。
五、延迟贡献账本
| 阶段 | 主要耗时 | 典型量级(示例) | 优化方向 |
|---|---|---|---|
| TCP 三次握手 | 1 RTT | 20–80 ms | 连接复用、TCP Fast Open |
| TLS 1.2 完整握手 | 2 RTT + 非对称运算 | 40–160 ms | 升级 TLS 1.3、会话恢复 |
| 证书验证 | 链验证 + OCSP | 0–100 ms | OCSP Stapling、缩短链 |
| 密钥交换计算 | ECDHE 标量乘 | 0.1–1 ms | 选用高效曲线、硬件加速 |
| TLS 1.3 完整握手 | 1 RTT | 20–80 ms | 默认启用 |
| TLS 1.3 会话恢复 | 1 RTT 或 0 RTT | 0–40 ms | PSK、0-RTT(幂等场景) |
ssl_handshake_time)、恢复率与 0-RTT 接受率,而不是只看单次连接时间。