3. SSL/TLS 基础知识回顾归纳总结

聊灰度发布中的 TLS 版本兼容之前,咱们得先把 SSL/TLS 的底子理清楚。说实话,很多同学做灰度时一遇到握手失败、证书报错,就慌了神,其实就是基础概念没串起来。我当年第一次接手公司网关升级时也栽过跟头——改了 TLS 1.2 支持,结果一台老设备连不上,排查了大半天才发现是协议版本协商的锅。嗯,这部分你弄明白了,后续验证方法才好落地。

3.1 TLS 是什么?从 SSL 到 TLS 的演变

TLS(传输层安全协议)前身是 Netscape 公司开发的 SSL。上世纪 90 年代 SSL 3.0 成型,后来 IETF 把它标准化,改名叫 TLS 1.0。说白了,就是给 TCP 套上一层加密护盾。

  1. SSL 3.0(1996)—— 有严重漏洞,现在基本弃用。我经历过的安全扫描里,只要扫出 SSL 3.0 就会被判高危。
  2. TLS 1.0(1999)—— 本质是 SSL 3.1,但改名了。已不推荐,很多合规要求已禁止。
  3. TLS 1.1(2006)—— 加了防 CBC 攻击的机制,但依然老旧。
  4. TLS 1.2(2008)—— 目前主流,我建议生产环境至少要求这个版本。
  5. TLS 1.3(2018)—— 握手机制大幅简化,性能和安全都更好。
版本 发布年份 安全等级 灰度兼容常见问题
SSL 3.0 1996 极低 POODLE 攻击风险,必须禁用
TLS 1.0 1999 低 BEAST 攻击,PCI DSS 已禁止
TLS 1.1 2006 中 部分支付行业仍要求,但正被淘汰
TLS 1.2 2008 高 灰度升级中兼容最好的版本
TLS 1.3 2018 极高 旧客户端可能不支持,需回退策略
注意: 灰度发布中,如果你同时开启 TLS 1.2 和 TLS 1.3,务必要确认服务端证书链和中间件是否支持 1.3 的签名算法。我曾经遇到过一个国产中间件不支持 TLS 1.3 的 ECDSA 证书,折腾了一周——最后发现是底层加密库没更新。

3.2 TLS 握手过程——核心流程

TLS 握手就是一个「先打招呼,再干活」的过程。客户端和服务端先交换能力,协商出对称密钥,然后才开始加密通信。为什么需要这个步骤?因为非对称加密太慢了,不能直接用。

我画了一张图帮你把 TLS 1.2 和 TLS 1.3 的握手对比起来看——

下面的 SVG 展示了 TLS 握手的核心节点。你可以对比两个版本,注意 1.3 比 1.2 少了一次往返。
TLS 1.2 vs TLS 1.3 握手流程对比 TLS 1.2 ① ClientHello ② ServerHello + 证书 ③ 密钥交换 (RSA/ECDHE) ④ ChangeCipherSpec ⑤ 握手完成 (Finished) ⑥ 加密数据传输 TLS 1.3 ① ClientHello (含 key_share) ② ServerHello + 证书 + 密钥 (只需1次往返) ③ Finished + 加密数据传输 ④ 应用层加密流量 💡 说明: TLS 1.3 把密钥交换提前到 ClientHello 中,省掉了 ChangeCipherSpec 和一次往返延迟(RTT), 同时移除了不安全的算法。灰度中切换到 1.3 后,你会发现新设备加载更快,但旧设备可能无法握手。
小技巧: 灰度发布时,如果服务端同时支持 TLS 1.2 和 1.3,你可以观察客户端的加密套件协商情况。我习惯在服务端日志里记录 negotiated_version 字段,一旦发现大面积回退到 1.2,说明这批灰度机器里有很多老旧中间件。

3.3 加密套件与密码学原语

每次握手,客户端和服务端还要商量「用什么密码算法来加密」。这个套餐就叫加密套件(Cipher Suite)。举个例子:

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
│         │         │           │
│         密钥交换   │           哈希算法
│                   对称加密+模式

拆开来看:

  • 密钥交换算法:ECDHE(椭圆曲线 Diffie-Hellman 临时密钥)是目前推荐的选择。RSA 密钥交换因为不具备前向安全性,已经在 TLS 1.3 中被移除了。
  • 认证算法:RSA 或 ECDSA 证书签名。ECDSA 能用更短的密钥达到相同的安全强度,我个人偏好用它。
  • 对称加密和模式:AES 128 GCM 是黄金标准。CBC 模式在 TLS 1.2 仍可用,但有安全隐患(Padding Oracle 攻击)。
  • PRF / 消息认证码:SHA256 是底线,SHA384 更安全。

灰度发布中,你可能会把一批新服务器升级到只支持 «TLS 1.3 + ECDHE + AES 256 GCM» 的强配置。这时候要是旧客户端只支持 «TLS 1.2 + RSA + AES 128 CBC»,握手直接失败。所以必须做版本兼容验证 —— 这就是咱们课程后面要讲的核心。

3.4 证书链与信任模型

TLS 的安全性依靠证书链来保证。服务端在握手时把证书发给客户端,客户端检查签发者直到根证书。这个过程叫链验证。

  • 根证书:预装在系统或浏览器里,自己签自己。自签名证书在内部灰度环境常用,但要注意客户端必须导入根证书。
  • 中间证书:由根证书签发,再签发服务器证书。很多企业用私有 CA,中间证书过期常导致灰度应用连接失败。
  • 服务器证书(叶子证书):包含域名和公钥,有效期通常 1 年。
避坑: 我曾经在灰度升级时简化了证书链,只配了叶子证书没配中间证书。结果某些 Android 设备报「证书路径不可信」——因为它们未预装中间 CA。记住:服务端必须发送完整证书链(叶子 + 中间证书,不包含根)。

3.5 TLS 版本兼容性核心要素

明白以上基础后,我再把灰度发布中你必须关注的维度列个清单:

维度 说明 灰度验证关注点
版本协商 ClientHello 发送最高支持版本,服务端选择 服务端是否降级到旧版本?导致安全性下降
加密套件 旧客户端可能不支持 GCM 模式 灰度期间必须保留主流 CBC 或 GCM 套件
证书算法 TLS 1.3 要求签名算法更严格 检查 ECDSA 证书是否被旧中间件支持
SNI(服务器名称指示) 现代 TLS 必须,但某些 IoT 设备不支持 灰度范围里有没有不支持 SNI 的客户端?
OCSP Stapling 1.3 中更常见,1.2 可能不启用 开启后可能影响旧版本客户端的证书验证

说实话,你把前面这些基础梳理清楚,灰度发布里遇到 TLS 版本兼容问题时,至少有方向去排查。我记得有一次在内部工具灰度中,客户端报了 «handshake failure»,看日志里版本协商到了 TLS 1.2,但加密套件却返回了 «no shared cipher»——最后发现是服务端只配了 ECDSA 证书,而客户端不支持 ECDSA。这就是基础没对齐的典型。

一句话总结: 灰度前先做版本和套件的矩阵测试;灰度中一定要保留降级能力(至少开放 TLS 1.2);同时监控客户端版本分布,避免突然切断老设备。