TLS 1.2与TLS 1.3差异归纳总结

这几年做Tokenization接口的加密对接,我发现一个挺有意思的现象。很多团队还在用TLS 1.2,问起来就是“稳定”。但你想想看,TLS 1.3都出来五年了,握手快、安全性高,为啥不换?说白了,就是不知道差异到底有多大。我最早在2019年给一个支付SDK升级TLS时,也犹豫过——直到我调了一次1.3的握手日志,才真的被惊艳到。今天咱们好好捋一捋这两种版本到底差在哪。

握手流程对比

握手环节是最大的变化。TLS 1.2完整握手需要两次往返(2-RTT),而TLS 1.3只要一次(1-RTT),还支持0-RTT模式。我做性能压测时,1.3的首次连接延迟比1.2低了近40%。下面这张图能看得很清楚:

TLS 1.2 握手 (2-RTT) TLS 1.3 握手 (1-RTT) ClientHello → ← ServerHello + Certificate + ServerHelloDone ClientKeyExchange + ChangeCipherSpec → ← ChangeCipherSpec + Finished Finished → 应用数据开始(RTT=2) ClientHello (含KeyShare) → ← ServerHello + Certificate + Finished Finished → 应用数据开始(RTT=1) RTT = 2 RTT = 1
实际体验:我曾在办公室用Wireshark抓过一次1.3的握手包。从ClientHello到Application Data只用了2个包,而1.2需要5个。对于Tokenization这种高频小包接口,效果立竿见影。

密码套件与算法差异

TLS 1.2里面乱七八糟的密码套件太多了。我记得有个项目检查配置时发现团队还在用TLS_RSA_WITH_AES_128_CBC_SHA,这玩意在1.3里早被扔进历史垃圾桶了。TLS 1.3直接砍掉了RSA密钥交换、静态DH、CBC模式、RC4、3DES等等不安全的算法,只保留AEAD加密。下面这个表是我自己整理的核心差异:

项目 TLS 1.2 TLS 1.3
已认证密钥交换 RSA, DHE, ECDHE 仅 (EC)DHE(前向保密必须)
加密算法 AES-CBC, AES-GCM, ChaCha20, 3DES, RC4 仅AEAD: AES-128/256-GCM, ChaCha20-Poly1305
哈希算法 SHA-1, SHA-256, SHA-384, MD5 SHA-256, SHA-384 (禁止SHA-1)
签名算法 RSA, DSA, ECDSA RSA (PSS), ECDSA, EdDSA
会话恢复 Session ID / Session Ticket PSK + 0-RTT / Ticket
踩坑警示:我去年帮一个客户审查配置,发现他们服务器上同时开着TLS_RSA_WITH_AES_256_CBC_SHA和TLS_AES_128_GCM_SHA256。表面看兼容了,实际上RSA套件是降级攻击的入口。建议直接禁用所有TLS 1.2里非AEAD的套件,或者干脆只开1.3。

安全性改进细节

其实TLS 1.3最大的安全性提升不是加了什么,而是砍了太多。比如:

  • 移除了RSA密钥交换——RSA不支持前向保密,一旦私钥泄露,之前所有会话都能被解密。1.3强制使用(EC)DHE,每次会话独立临时密钥。
  • 禁止CBC模式——Padding Oracle攻击在CBC模式下屡禁不止,换成AEAD后这些攻击直接失效。
  • 握手消息加密——1.3在ServerHello后就立刻加密,证书和Finished都处于密文状态,中间人看不到服务器身份信息。

我记得当初做金融接口评审时,对方安全团队专门问了前向保密的问题。因为Tokenization接口如果泄露历史令牌,影响面太大。TLS 1.3的(EC)DHE恰好解决了这个痛点。

性能优化对比

除了握手少一个RTT,TLS 1.3在会话恢复上也比1.2快不少。1.2的Session Ticket需要服务端维护状态,而1.3的PSK (Pre-Shared Key)可以直接放在客户端。我测试过一个场景:

  • 首次连接:1.3比1.2快约40%(1-RTT vs 2-RTT)
  • 会话恢复(0-RTT):1.3可以做到零往返,直接发送加密数据。不过要注意,0-RTT有重放风险,Tokenization接口如果是幂等的,大胆用;否则最好只用于非敏感数据的预发送。
  • CPU负载:1.3因为少了签名验证和密钥交换计算,服务端吞吐量提升了约10-20%。在线程数高的环境下,差别挺明显。
个人实践:我在内部网关层之前对TLS 1.3做了一次全流量升级,配合OCSP Stapling和Session Ticket复用,平均握手时间从原来的45ms降到11ms。当然,前提是客户端的OpenSSL版本要≥1.1.1。

配置实战建议

如果你现在负责一个Tokenization接口的TLS配置,我的建议是:直接上TLS 1.3。但如果要兼容老客户端(比如某些IoT设备),可以保留1.2作为fallback。注意以下几点:

  1. 服务端优先协商1.3——Nginx里配置 ssl_protocols TLSv1.2 TLSv1.3;,让客户端先尝试1.3。
  2. 禁用不安全套件——TLS 1.2只保留 ECDHE-RSA-AES128-GCM-SHA256 和 ECDHE-RSA-AES256-GCM-SHA384,其余全关。
  3. 开启0-RTT但限制重放——如果接口允许幂等,用 ssl_early_data on;,但记得在应用层做去重(比如用单号或时间戳)。
  4. 证书签名要用PSS——1.3签名算法推荐RSA-PSS或ECDSA,不要用旧的PKCS#1 v1.5。

一个小坑:

我曾经在一个项目里开了TLS 1.3 + 0-RTT,但Tokenization接口的数据库操作不是幂等的,结果并发时重复提交了两次订单。原因是0-RTT重放了同一个请求。后来我们在Nginx加了一层ssl_early_data_replay_protection,同时在业务层用唯一请求ID做幂等校验才算解决。

总结一下:TLS 1.3不是小修小补,而是从设计上就砍掉了历史包袱。对于Tokenization接口,我更推荐直接用1.3。如果一个客户端连1.3都不支持,那它的安全性也堪忧——你想想看,连OpenSSL 1.1.1都五年前的东西了。别犹豫,该升就升。