3. TLS 1.2 vs TLS 1.3:握手的“降龙十八掌”与“一阳指”

讲握手优化,绕不开 TLS 1.2 和 1.3 的对比。我入行那阵子,TLS 1.2 还是标配,后来 1.3 出来,第一反应是“多了一轮握手?”。其实刚好相反,1.3 把握手压缩到 1-RTT,甚至 0-RTT,变化相当大。

说白了,TLS 1.2 握手像一套复杂的“降龙十八掌”——招式多,容错强,但慢。TLS 1.3 像“一阳指”——精准,快,少废话。咱们今天就拆开看看。

3.1 握手流程:从 2-RTT 到 1-RTT

先看最直观的差异:往返次数。

  • TLS 1.2:完整握手需要 2 次 TCP RTT + 2 次 TLS RTT。一共 4 个握手包(ClientHello → ServerHello + Certificate → ClientKeyExchange → Finished)。
  • TLS 1.3:完整握手只需 1 次 TLS RTT。ClientHello 直接带密钥协商参数,ServerHello 后服务器就把证书和 Finished 合并发回来。

我在一个跨国 API 网关项目里验证过:从北京连美东,TLS 1.3 比 1.2 平均快 120ms。用户体感提升很明显,尤其移动端。

核心结论:TLS 1.3 用更少的交互完成了同样的安全目标,减少了网络延迟对用户的折磨。

3.2 密码套件:大瘦身

TLS 1.2 密码套件列表长得像购物清单。我记得有一次配置 Nginx,光密码套件就写了二十行,还要考虑各种兼容性。TLS 1.3 砍了一大刀,只保留 5 个强密码套件。

特性 TLS 1.2 TLS 1.3
支持的密码套件数量 超过 30 种(含大量已废弃) 5 种(TLS_AES_128_GCM_SHA256 等)
密钥交换算法 RSA / DH / ECDH(可选向前保密) 仅 ECDHE / DHE(强制向前保密)
签名算法 RSA / DSA / ECDSA 仅 RSA / ECDSA / EdDSA
对称加密 多种:AES-CBC / AES-GCM / ChaCha20 等 仅 AEAD(AES-GCM / ChaCha20)
MAC HMAC + 加密(MAC-then-Encrypt 或 Encrypt-then-MAC) 内嵌在 AEAD 中

为什么要瘦身?你想想看,选项越多,攻击面越大。TLS 1.3 直接禁止了 RSA 密钥交换、CBC 模式、RC4、3DES 等一堆老弱病残。我前两年还帮客户排查过一个 1.2 降级攻击的案例:客户端被中间人强制协商到脆弱的密码套件——换成 1.3 后,这类问题就消失了。

我的建议:新服务直接上 TLS 1.3,只开 AEAD 密码套件。老服务先开启 1.2 + 1.3 双栈,然后逐步淘汰弱套件。

3.3 证书验证与握手流程简化

TLS 1.2 的证书通常是服务器在 ServerHello 之后单独发,客户端再校验。TLS 1.3 把证书和 Finished 合并在一起,好处是减少了握手分片,坏处是证书链大的话,第一个数据包可能装不下,需要额外等待。但这是小概率事件。

另外,1.3 还去掉了 Change Cipher Spec 协议。这个在 1.2 里是独立报文,1.3 里变成了纯兼容包袱——只为了兼容老设备,实际握手用不到。

3.4 0-RTT:快但要注意安全

TLS 1.3 最大的亮点是 0-RTT 会话复用。它允许客户端在第二次连接时直接把应用数据随 ClientHello 发出去,服务器即刻处理。我在一个实时聊天系统里用过,首次消息延迟从 200ms 降到了 40ms。

注意:0-RTT 存在重放攻击风险。因为你第一次的请求数据被提前发送,如果攻击者截获这个包,可以重复提交。我曾经踩过这个坑:生产环境上线第二天就发现订单重复创建。解决方案是在应用层加“防重放令牌”。

简单来说,0-RTT 适合幂等请求(如 GET、心跳、状态上报),不适合支付、下单等操作。除非你做好了重放检测。

3.5 我的一张对比流程图

下面这张图总结了 TLS 1.2 和 1.3 的核心握手差异。你一看就明白。

TLS 1.2 vs TLS 1.3 握手流程对比 TLS 1.2 (2-RTT) ① ClientHello (密码套件列表) ② ServerHello + 证书 + 密钥交换 ③ 客户端密钥交换 + Change Cipher Spec ④ 服务端 Finished + 应用数据 延迟:≈ 2 × RTT + 证书验证 安全:支持多种弱套件,易降级 TLS 1.3 (1-RTT / 0-RTT) ① ClientHello (密钥共享 + 密码套件) ② ServerHello + 证书 + Finished (密钥协商+身份验证合并) ③ 客户端 Finished + 应用数据 延迟:≈ 1 × RTT + 证书验证 0-RTT:首次数据包即可发应用数据 安全:强制向前保密,只有强套件 注意:0-RTT 需防重放攻击

3.6 实际选型建议

  1. 尽量启用 TLS 1.3。无论是浏览器、移动端还是后端服务,现代库都已支持。你只要配置 Nginx 或 OpenSSL 版本够新。
  2. 1.2 做降级兜底。如果客户端不支持 1.3,自动回退到 1.2。但务必禁用 RCA、CBC、3DES 等。
  3. 0-RTT 谨慎用。只在幂等场景放开,应用层加唯一 ID 做去重。
  4. 证书链保持精简。TLS 1.3 的合并数据包可能因为你证书链太长而触发 TCP 分片,反而变慢。我用 Let's Encrypt 时就去掉中间交叉证书,直接发叶子+根。

一句话总结:TLS 1.3 解决了我当年调优 1.2 握手时的几乎所有痛点。如果你还在用纯 1.2,该升级了。