1. TLS 概述:为什么需要 TLS?从 HTTP 到 HTTPS 的演进,TLS 1.2 vs TLS 1.3 核心区别

1.1 为什么需要 TLS?—— 一个真实的故事

先讲个我亲身经历的事。几年前,我帮一家电商平台做安全审计。他们的 App 还在用纯 HTTP 跟后端通信。我说这不行,太危险了。对方架构师反问:「数据又不是明文存的,怕什么?」

嗯,问题就在这里。很多人以为「数据在服务器里加密了」就安全了。但数据在网络上传输时,完全是裸奔的。

你想想看,HTTP 请求从你的手机到服务器,中间要经过多少个路由器、交换机、基站?任何一个环节被劫持,你的密码、信用卡号、聊天记录,全都能被直接看到。

这就是 TLS 要解决的核心问题:在不安全的网络上,建立一条安全的通信通道。

TLS 的三个核心目标:

  • 机密性 —— 数据只有通信双方能看懂,中间人拿到的是一堆乱码
  • 完整性 —— 数据在传输过程中没有被篡改,哪怕改了一个比特也能检测出来
  • 身份认证 —— 你连接的那个服务器,确实是它声称的那个,不是冒牌货

1.2 从 HTTP 到 HTTPS:到底多了什么?

说白了,HTTPS 就是 HTTP 外面套了一层 TLS。我习惯用一个比喻:HTTP 是明信片,谁都能看;HTTPS 是装在保险箱里的信,只有收件人能打开。

具体来说,HTTPS 比 HTTP 多了两个东西:

  • TLS 握手阶段 —— 通信双方先协商加密算法、交换密钥、验证证书
  • TLS 记录层 —— 所有应用数据都被加密、分段、加上 MAC(消息认证码)

我曾经在项目中遇到过一个问题:某团队把 HTTPS 部署好了,但性能下降明显。查了半天,发现是 TLS 握手每次都要 2-RTT,对于短连接来说开销太大了。后来我们启用了会话复用,才把延迟降下来。

小提示:HTTPS 的额外开销主要在握手阶段。一旦连接建立,对称加密的加解密速度其实很快,现代 CPU 甚至硬件加速了 AES 和 ChaCha20。

1.3 TLS 1.2 vs TLS 1.3:核心区别在哪?

我刚开始做安全开发时,TLS 1.2 还是主流。后来 TLS 1.3 出来,我第一反应是「又来个新版本,兼容性又要头疼了」。但真正用上之后,我只想说:真香。

先看一张对比表:

对比维度 TLS 1.2 TLS 1.3
握手延迟 2-RTT(完整握手) 1-RTT(完整握手),0-RTT(复用)
支持的密码套件 30+ 种组合,很多已不安全 仅 5 种,全部强制前向安全
密钥交换 支持 RSA、DH、ECDH 等 仅支持 (EC)DHE,废弃 RSA 密钥交换
签名算法 支持 SHA-1、SHA-256 等 强制使用 SHA-256 及以上
会话恢复 Session ID / Session Ticket PSK + 0-RTT
协议复杂度 高,很多可选扩展 低,精简了握手消息

1.3.1 握手速度:从 2-RTT 到 1-RTT

这是最直观的改进。TLS 1.2 完整握手需要两次往返:

  1. ClientHello → ServerHello + Certificate + ServerKeyExchange + ServerHelloDone
  2. ClientKeyExchange + ChangeCipherSpec + Finished → ChangeCipherSpec + Finished

TLS 1.3 把很多步骤合并了:

  1. ClientHello(含密钥共享) → ServerHello + Certificate + Finished
  2. Client Finished → 开始传输数据

我记得有一次给一个金融客户做优化,他们的 API 网关每天处理上亿次短连接。从 TLS 1.2 升级到 1.3 后,握手延迟直接降了一半,服务器 CPU 占用也降了 30%。

1.3.2 安全性:砍掉不安全的选项

TLS 1.2 的问题在于「兼容性太好」。为了兼容老系统,保留了太多不安全的密码套件。比如 RSA 密钥交换,它没有前向安全性——一旦私钥泄露,所有历史通信都能被解密。

我曾经在审计一个遗留系统时发现,它还在用 TLS 1.2 + RSA + CBC 模式。我跟他们说:「这跟裸奔区别不大。」对方还不信,直到我演示了如何用抓包工具配合私钥解密所有流量……

TLS 1.3 直接砍掉了:

  • RSA 密钥交换
  • CBC 模式(只保留 AEAD)
  • 静态 DH
  • 压缩
  • 重协商

警告:如果你还在用 TLS 1.2,请务必禁用以下密码套件:

  • 所有基于 RSA 密钥交换的套件
  • 所有 CBC 模式套件
  • 所有使用 SHA-1 的套件

只保留 ECDHE + AES-GCM / ChaCha20-Poly1305 的组合。

1.3.3 0-RTT:快,但有代价

TLS 1.3 引入了一个新特性:0-RTT 数据。如果客户端之前跟服务器握过手,可以缓存 PSK(预共享密钥),下次直接发送加密数据,不需要任何往返。

但这里有个坑。0-RTT 数据存在重放攻击的风险。我建议只在幂等请求上使用 0-RTT,比如 GET 请求。对于 POST、PUT 这类会改变状态的请求,最好还是走完整握手。

1.4 一张图看懂 TLS 演进

下面这张图展示了从 HTTP 到 HTTPS,再到 TLS 1.2 和 TLS 1.3 的核心变化:

TLS 演进核心逻辑 HTTP 明文传输,无加密 HTTPS HTTP + TLS 加密通道 TLS 1.2 2-RTT,30+ 密码套件 ↓ 演进方向:更快、更安全、更简洁 TLS 1.2 特点 • 握手需要 2 次往返(2-RTT) • 支持 RSA / DH / ECDH 密钥交换 • 30+ 密码套件,含不安全选项 • 支持 CBC 模式(易受 padding oracle 攻击) TLS 1.3 改进 • 握手仅需 1 次往返(1-RTT) • 仅支持 (EC)DHE,强制前向安全 • 仅 5 种密码套件,全部 AEAD • 支持 0-RTT,减少延迟 核心结论 TLS 1.3 比 1.2 更快(减少 1-RTT)、更安全(砍掉不安全算法) 生产环境建议:优先启用 TLS 1.3,降级兼容 TLS 1.2

1.5 我的建议:现在就用 TLS 1.3

如果你问我,新项目该用哪个版本?我的答案很明确:优先 TLS 1.3,降级兼容 TLS 1.2。

为什么?

  • 性能更好 —— 1-RTT 比 2-RTT 快,0-RTT 更是秒开
  • 更安全 —— 没有历史包袱,默认就是最佳实践
  • 生态成熟 —— 主流浏览器、操作系统、库都已支持

但也要注意,有些老系统可能不支持 TLS 1.3。比如某些嵌入式设备、旧版 Java(8u261 之前)、Windows 7 上的 IE。这时候需要保留 TLS 1.2 作为降级选项。

部署检查清单:

  1. 确认服务端库版本支持 TLS 1.3(OpenSSL 1.1.1+、BoringSSL、NSS 等)
  2. 配置密码套件优先级:TLS_AES_128_GCM_SHA256 > TLS_AES_256_GCM_SHA384 > TLS_CHACHA20_POLY1305_SHA256
  3. 禁用 TLS 1.0 / 1.1(它们已经不安全了)
  4. 启用会话复用(Session Ticket 或 PSK)
  5. 测试兼容性:用 ssllabs.com 或 openssl s_client 验证