TLS 1.2 与 TLS 1.3 握手的主要区别
这个问题我面试时几乎必问。为什么?因为握手流程的差异,直接反映了 TLS 协议从“兼容性优先”到“安全+性能优先”的转变。我当年在一个金融支付项目中,硬着头皮把业务从 TLS 1.2 迁移到 1.3,中间踩了不少坑。今天就跟你聊聊,这两个版本握手到底差在哪。
握手轮次:从 2-RTT 压缩到 1-RTT
先说最直观的差别。TLS 1.2 完整握手需要两次来回(2-RTT)。1.3 只用了一次,而且它还提供了 0-RTT 数据发送,前提是你之前已经建立过会话。嗯,我知道你可能会问:那一趟省在哪了?
看下面这个表格就清楚了。我把两个版本的核心握手步骤列出来,你可以对比着看。
| 步骤 | TLS 1.2 | TLS 1.3 |
|---|---|---|
| 1 | Client → Server: ClientHello (密码套件、随机数、Session ID) | Client → Server: ClientHello (密码套件、key_share、PSK) |
| 2 | Server → Client: ServerHello + Certificate + ServerHelloDone | Server → Client: ServerHello + EncryptedExtensions + Certificate + CertificateVerify + Finished |
| 3 | Client → Server: ClientKeyExchange + ChangeCipherSpec + Finished | Client → Server: (证书验证) + Finished |
| 4 | Server → Client: ChangeCipherSpec + Finished | (握手结束,开始应用数据) |
| RTT | 2 | 1 |
密码套件与密钥交换:1.3 砍掉了哪些“老古董”?
第二个大区别,密码套件协商方式变了。TLS 1.2 允许服务器从一堆套件里选,密钥交换可以用 RSA、DHE、ECDHE,甚至 static DH。嗯,这里就有安全风险。比如 RSA 密钥交换不支持前向安全性(PFS)。我曾在一次审计中发现,公司用了 TLS_RSA_WITH_AES_128_CBC_SHA,私钥一旦泄露,历史流量全完蛋。
TLS 1.3 直接砍掉了所有非 PFS 的密钥交换,强制只有 DHE 与 ECDHE。同时,加密套件从几十种精简到5 种,全是 AEAD 模式(AES-GCM、ChaCha20-Poly1305等)。你看这个变化——
- TLS 1.2 常见套件举例:
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(签名+密钥交换+加密+MAC,四个部分混在一起) - TLS 1.3 套件举例:
TLS_AES_128_GCM_SHA256(只定义加密+哈希,密钥交换由扩展key_share独立协商)
关键思维转变:1.3 把“密钥交换算法”从密码套件里剥离了。签名算法在 CertificateVerify 独立协商,密钥交换在 key_share 扩展里搞定。密码套件只负责对称加密 + HMAC。这样每个环节的妥协空间就小了。
会话恢复:从 Session ID / Ticket 到 PSK
最早 TLS 1.2 用 Session ID 做恢复,服务器得存状态。后来有了 Session Ticket(RFC 5077),客户端自己存加密票证。但无论哪种,恢复时都要额外交换一次。TLS 1.3 直接抛出了 PSK(预共享密钥)机制。客户端在手握之前的主密钥后,可以直发一个 PSK 扩展,把握手压缩到 0-RTT(当然 0-RTT 有重放风险,要应用层兜底)。
我曾经处理过一个高并发 API 网关,客户端每次连接都走完整握手,延迟 80ms。后来切到 PSK 恢复,大部分连接直接 0-RTT 发数据,延迟降到 15ms。收益非常明显,但要注意:0-RTT 的数据不能保证幂等操作,比如支付要加防重放。
其他重要区别
除了上面这些,还有几个细节。我说几个我踩过的——
- CertificateVerify 签名内容:1.2 签的是握手消息的 hash,但 1.3 签的是 transcript hash(包含双方所有握手消息)。攻击者更难篡改协商过程。
- HelloRetryRequest:1.3 引入了这个新消息。当服务器不支持客户端发来的密钥交换组时,它会要求客户端换个曲线重发 ClientHello。我调试时第一次看到这个,还以为客户端发错了。
- ChangeCipherSpec 的地位:1.3 里它的出现仅用于兼容中间盒,不会触发任何加密状态迁移。如果你在抓包时看到多出来的 CCS,直接忽略就好。
一张图理解握手差异
上面这张图应该能帮你直观理解“少一趟”的含义。1.3 把证书和 Finished 打包在 ServerHello 之后一起发,客户端拿到就能直接算密钥,不用再交换 ClientKeyExchange 了。