第3章:加密套件与密钥交换 —— 对称/非对称加密、DH/ECDHE、RSA、AES-GCM

这一章,我们聊聊 TLS 握手里的核心——加密套件和密钥交换。说白了,就是客户端和服务端到底怎么商量着用一把锁,把数据锁起来。

我职业生涯里,最头疼的一次就是客户线上环境突然握手失败,查了大半天,最后发现是服务端把 DH 参数配死了,但客户端只支持 ECDHE。从那以后,我对密钥交换的兼容性就特别敏感。

一句话总结本章核心: 对称加密效率高,用来加密实际数据;非对称加密和 DH 族算法用来安全地协商出对称密钥。TLS 1.2 里,你配的 cipher suite 决定了这一切。

3.1 对称加密 vs 非对称加密 —— 各司其职

先说说为什么 TLS 不是只用一种加密。

对称加密:加密和解密用同一个密钥。比如 AES,速度快,能扛住大数据量。但问题来了——这个密钥怎么安全地传给对方?

非对称加密:一对钥匙,公钥加密、私钥解密。RSA 就是代表。但非对称加密太慢了,比 AES 慢上千倍,不能拿来直接加密整条 HTTPS 流量。

所以 TLS 的做法是混搭:用非对称加密或 DH 族算法先商量出一个临时对称密钥,后面的数据全部用 AES 这类对称加密来保护。

维度对称加密(如 AES)非对称加密(如 RSA)
速度极快(硬件加速后 Gbps 级)慢(通常用于小数据)
密钥数量双方持有同一把公钥/私钥对
典型用途加密 HTTP 请求体、响应体签名、密钥传输
注意: 不要试图用非对称加密直接加密整个应用数据。不仅慢,而且密钥泄露后所有历史流量都能被解密——因为固定了私钥。

3.2 密钥交换三剑客:RSA、DH、ECDHE

密钥交换就是解决「怎么安全地把对称密钥告诉对方」。TLS 1.2 常见三种方式:

3.2.1 RSA 密钥传输

客户端生成一个随机密钥(Pre-Master Secret),用服务器的 RSA 公钥加密后发给服务器,服务器用私钥解密得到密钥。

简单吧?但问题很明显——私钥一旦泄露,之前所有用这个私钥加密过的会话都能被解密。(这叫缺乏前向安全性)

我曾经审计过一个老旧系统,还在用纯 RSA 密钥交换的加密套件。我跟他们说:万一哪天私钥被偷了,过去三年的聊天记录全白给。后来他们连夜升级到了 ECDHE。

3.2.2 DH(Diffie-Hellman)

DH 交换不需要传输密钥本身。双方各自生成私有数,然后通过公开交换的参数计算出相同的共享密钥。即使攻击者截获了所有公开参数,也算不出最终密钥。

不过经典 DH 也有弱点:每次握手要生成大数运算,性能开销大。

3.2.3 ECDHE(Elliptic Curve Diffie-Hellman Ephemeral)

这是我现在最喜欢用的。ECDHE = 椭圆曲线 + DH + 临时密钥。

  • 椭圆曲线:用更短的密钥长度达到相同安全强度(256 位椭圆曲线 ≈ 3072 位 RSA)
  • Ephemeral:每次握手都生成一对临时密钥对
  • 好处:即使服务器长期私钥泄露,之前的会话密钥也无法被推算——完美前向安全性(PFS)
我的经验: 新系统推荐只启用 ECDHE 系列的加密套件,比如 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256。既保证前向安全,又能兼容现有证书体系。

3.3 AEAD 与 AES-GCM

加密套件中后半部分通常是 ..._AES_128_GCM 或 ..._AES_256_GCM。

AES-GCM 是一种认证加密(AEAD)模式,同时提供机密性和完整性校验。以前老式的 CBC 模式容易受到 Padding Oracle 攻击,我见过不止一次因为 CBC 模式配置不当导致业务数据被篡改的事故。

GCM 呢?它把加密和 MAC 合并了,不再需要单独的 HMAC 步骤。性能更好,也更安全。

加密模式完整性抗重放常见攻击
AES-CBC需额外 HMAC弱Padding Oracle、Lucky13
AES-GCM内建强极少(除非 Nonce 重用)
ChaCha20-Poly1305内建强极少(防硬件加速差场景)
小贴士: 在移动端或低端硬件上,ChaCha20-Poly1305 有时比 AES-GCM 更快(因为 AES 需要专用指令集加速)。所以我一般推荐服务端同时支持 GCM 和 ChaCha20,让客户端自己选。

3.4 一张图看懂密钥交换与对称加密流程

TLS 1.2 密钥交换与对称加密流程(ECDHE + AES-GCM) 客户端 服务端 ① 客户端支持的加密套件列表 ② 服务端选择 ECDHE_RSA_WITH_AES_128_GCM ③ 服务端 ECDHE 临时公钥 + 数字签名 ④ 客户端 ECDHE 临时公钥 共享密钥 = ECDHE(PriC, PubS) 共享密钥 = ECDHE(PriS, PubC) ⑤ AES-128-GCM 加密数据 ⑤ AES-128-GCM 解密数据 双向加密流量

这张图画了经典流程:客户端先打招呼;服务端决定用 ECDHE + AES-GCM;双方各自发临时公钥;各自算出相同共享密钥;之后所有应用数据都用 AES-GCM 加密传输。

3.5 实际配置中的坑与建议

3.5.1 不要用 DH 或 DHE 字样的套件(在 2025 年)

非椭圆曲线的 DH 性能差、参数大,现在主流浏览器已经基本抛弃。如果你还在用,大概率是老旧系统。

3.5.2 优先级:ECDHE + GCM / ChaCha20

我推荐服务端把 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 放在第一个。如果客户端支持,握手立刻完成。

3.5.3 证书算法和密钥交换是两回事

很多人搞混:ECDHE_RSA 的意思是密钥交换用 ECDHE,签名验证用的是 RSA 证书。你证书完全可以还是 RSA,不影响前向安全。别为了换算法去重新申请 ECDSA 证书——虽然 ECDSA 证书更小更快,但兼容性问题更多。

一句话归纳: 加密套件 = 密钥交换算法 (ECDHE) + 身份认证算法 (RSA/ECDSA) + 对称加密模式 (AES-GCM) + 伪随机函数 (SHA256)。你在配置里看到的那串字符串,像 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,每个部分都有实义。

3.6 课后自测思维题

  • 如果服务端只支持 TLS_RSA_WITH_AES_128_CBC_SHA,客户端可能受到什么攻击?
  • 为什么 ECDHE 里的「E」如此重要?如果去掉「E」变成静态 DH,前向安全性还在吗?
  • 假设你的业务要求最高安全等级,你会把哪个加密套件放在首位?为什么?

嗯,这一章信息量不小。但别怕,你在配置服务器时只要记住两条:选 ECDHE,选 GCM。剩下的细节,都是帮你理解为什么这么选。下次你看到那一长串加密套件名字,就能像读车牌一样一眼看懂了。