第4章 常见密码套件详解
密码套件这个名字听起来挺唬人的,说白了就是“一组加密算法的组合”。我刚开始搞TLS配置时,面对一堆像 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 这样的长串,直接懵了。后来拆开看,其实每个部分都很清晰。
4.1 密码套件的骨架
一个标准的密码套件由四部分组成:密钥交换、身份认证、对称加密、消息认证码(MAC)或AEAD模式。拿最经典的一个例子来拆解:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
│ │ │ │ └── 哈希算法(用于PRF和HMAC)
│ │ │ └────────── 对称加密算法及其模式
│ │ └────────────────── 身份认证算法
│ └───────────────────────── 密钥交换算法
└──────────────────────────────── 协议前缀
你想想看,加密通信就像两个人隔着墙说话。密钥交换负责商量一个临时钥匙,身份认证确保对方不是冒充的,对称加密用来快速保密传输内容,哈希算法保证数据没被篡改。缺一个都不行。
| 组件 | 常见算法示例 | 作用 |
|---|---|---|
| 密钥交换 | ECDHE、DHE、RSA | 协商对称密钥(前向安全性依赖这里) |
| 身份认证 | RSA、ECDSA、DSA | 验证服务器/客户端身份 |
| 对称加密 | AES_128_GCM、AES_256_GCM、CHACHA20 | 实际数据加密 |
| 哈希+MAC | SHA256、SHA384、POLY1305 | 校验完整性及派生密钥 |
小经验:我习惯在配置前先看一眼套件名里的 ECDHE 或 DHE,只要有这个前缀,基本就支持前向安全了。没有?那就要小心了。
4.2 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
这个套件是目前互联网上最常用的组合之一。拆开看:
- ECDHE:椭圆曲线临时密钥交换,每次握手生成新的临时密钥对,就算服务端的长期私钥泄露,之前的会话也无法被解密(前向安全性)。
- RSA:用RSA证书来签名验证身份。ECDHE的临时公钥由RSA证书签名,客户端验证签名确认服务器身份。
- AES_256_GCM:AES 256位密钥,GCM模式同时提供加密和完整性校验,属于AEAD算法。出错了不会泄露明文。
- SHA384:用于伪随机函数(PRF)和握手消息的HMAC,比SHA256更安全。
我在项目里曾经遇到过一个案例:客户要求最高安全等级,但又必须兼容老旧Java 6客户端。ECDHE_RSA这套在大多数TLS 1.2实现里都跑得很好,但Java 6默认不支持GCM,得额外安装JCE包。嗯,这里要注意:高安全性往往意味着兼容性要付出代价。
推荐场景:需要前向安全性、对性能有一定要求、客户端较新(TLS 1.2+)的环境。这个套件在Nginx、Apache、OpenSSL 1.0.1+中均支持。
4.3 TLS_AES_128_GCM_SHA256
这是TLS 1.3的标配套件之一。TLS 1.3砍掉了大量不安全的交换和加密选项,密码套件只有五个左右。AES_128_GCM_SHA256 是最推荐的一个:
- 无显式密钥交换描述:TLS 1.3将密钥交换和身份认证移到了握手扩展中,套件名称只保留对称加密和哈希部分。
- AES_128_GCM:128位密钥,GCM模式,性能优于256位,且安全强度足够(至少在量子计算普及前)。
- SHA256:用于HKDF和握手完整性。
我个人特别喜欢TLS 1.3的这个设计——简单、高效、前向安全默认开启。配置TLS 1.3时,我基本只开 TLS_AES_128_GCM_SHA256 和 TLS_AES_256_GCM_SHA384 两个,偶尔加一个 TLS_CHACHA20_POLY1305_SHA256 给移动端备选。
| 套件 | TLS版本 | 密钥长度 | 前向安全 | 性能 |
|---|---|---|---|---|
| ECDHE_RSA_AES_256_GCM_SHA384 | 1.2 | 256 | 是 | 中等(DH计算) |
| AES_128_GCM_SHA256 | 1.3 | 128 | 是(默认) | 高(硬件加速) |
| ECDHE_ECDSA_AES_256_GCM_SHA384 | 1.2 | 256 | 是 | 高(椭圆曲线签名) |
别踩这个坑:我曾经在迁移到TLS 1.3时,想当然地把所有TLS 1.2的套件都复制到1.3配置里,结果发现服务端根本启动不了。TLS 1.3的密码套件名不带密钥交换前缀,直接写 AES_256_GCM_SHA384 就行,别手滑写上 ECDHE_RSA_...。
4.4 其他常见套件速览
除了上面两个,下面几个也经常遇到:
- TLS_CHACHA20_POLY1305_SHA256:TLS 1.3套件,移动端首选。软件实现快,没有AES硬件加速时性能优势明显。
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS 1.2套件,用ECC证书代替RSA,签名更快、密钥更短。我给自己搭的内部CA就用ECDSA证书,配合这套,握手快得飞起。
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:老套件了——DHE虽然前向安全,但CBC模式容易受padding oracle攻击,SHA256也不如GCM安全。建议直接禁用。
4.5 配置时的个人建议
回到实际配置环节,我一般会按以下优先级排序:
- TLS 1.3 套件:
TLS_AES_128_GCM_SHA256或TLS_AES_256_GCM_SHA384,现代浏览器都支持,性能最好。 - TLS 1.2 首选:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,如果你用RSA证书的话;如果用的是ECC证书,换成TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384。 - 移动端兜底:
TLS_CHACHA20_POLY1305_SHA256,尤其针对没有AES-NI的ARM设备。 - 不推荐的:所有CBC模式套件、RSA密钥交换套件(无前向安全)、RC4、3DES——这些我全部从配置里删掉。
一句话总结:密码套件不是越多越好。你想想看,每次握手时服务器和客户端要从列表里挨个试,list太长反而拖慢握手速度。我个人习惯只留6-8个套件,覆盖TLS 1.3和1.2的主流组合就够了。
4.6 一个真实例子
去年帮一个金融客户优化TLS配置,他们的Nginx配置里还挂着十几年前的老套件,比如 TLS_RSA_WITH_RC4_128_SHA。我查了日志,发现还有少量客户端在用,后来确认全部是老旧POS机。最终决定:在单独的子域名上提供降级配置,主域名只允许现代套件。改造完成后,TLS握手时间从平均120ms降到了45ms。嗯,虽然跟套件数量不完全直接相关,但清掉那些老古董确实让协商路径变短了。
千万不要:不要为了兼容而贪心保留所有套件。我曾经见过一份配置同时开了ECDHE_RSA和DHE_RSA,还有ECDHE_ECDSA,甚至还有已废弃的DHE_DSS——结果导致连接时双方协商出的总是最慢的DHE_DSS(因为某些客户端的偏好问题)。只保留你真正需要的那几类。