密码套件(Cipher Suite)选择:如何选择安全的密码套件,禁用不安全的套件

密码套件,说白了就是一组加密算法的组合。它决定了你的 SSL/TLS 连接怎么握手、怎么加密、怎么校验完整性。我见过太多开发者直接复制网上的配置,结果连 RC4 这种古董算法都没关掉。嗯,今天我们就来聊聊怎么选一套靠谱的密码套件。

密码套件长什么样?

一个典型的密码套件看起来像这样:

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

拆开来看,它包含四个部分:

  • 密钥交换算法:ECDHE(椭圆曲线 Diffie-Hellman 临时密钥)
  • 身份验证算法:RSA
  • 对称加密算法:AES_128_GCM
  • 消息认证码算法:SHA256

我个人习惯把密码套件想象成一个「安全工具箱」。每个工具负责一件事,组合起来才能保证通信安全。缺一个都不行。

哪些套件该禁用?

我在项目中遇到过不少坑,有些套件看起来能用,实际上已经漏洞百出。下面这张表是我整理的「禁用清单」:

套件类型 原因 替代方案
RC4 系列 存在多种攻击,已被 RFC 7465 明确禁止 AES-GCM
CBC 模式(如 AES-CBC) 易受 Padding Oracle 攻击 GCM / ChaCha20-Poly1305
3DES 密钥长度仅 112 位,不符合现代安全要求 AES-128 或更高
DSS / DSA 签名算法过时,性能差 ECDSA / EdDSA
静态 DH / RSA 密钥交换 不支持前向安全性(PFS) ECDHE / DHE
SHA-1 系列 碰撞攻击已成现实 SHA-256 或更高
⚠️ 警告: 我曾经在某个老项目中看到 RC4 还在用,原因是「兼容旧设备」。结果安全扫描直接亮红灯。别为了兼容性牺牲安全性,不值得。

推荐的密码套件列表

那么,该用哪些套件呢?我个人推荐以下组合,按优先级排序:

  1. TLS_AES_128_GCM_SHA256(TLS 1.3 默认)
  2. TLS_AES_256_GCM_SHA384(TLS 1.3 高安全)
  3. TLS_CHACHA20_POLY1305_SHA256(移动端推荐)
  4. TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(TLS 1.2)
  5. TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(TLS 1.2 兼容)

你想想看,为什么我特别推荐 ChaCha20-Poly1305?因为它在移动设备上性能极好。Android 设备大多有硬件加速的 AES,但有些低端机没有。ChaCha20 纯软件实现也能跑得飞快。我在做某款社交 App 时,切换到 ChaCha20 后握手时间缩短了 30%。

Android 中如何配置?

在 Android 上配置密码套件,主要通过 SSLSocketSSLEnginesetEnabledCipherSuites() 方法。来看代码:

// 获取 SSLSocketFactory
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket("api.example.com", 443);

// 定义允许的套件列表
String[] allowedSuites = new String[] {
    "TLS_AES_128_GCM_SHA256",
    "TLS_AES_256_GCM_SHA384",
    "TLS_CHACHA20_POLY1305_SHA256",
    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
};

// 设置套件
socket.setEnabledCipherSuites(allowedSuites);

// 开始握手
socket.startHandshake();
💡 小技巧: 不要硬编码套件列表。我建议从服务器端下发配置,或者用 SSLSocket.getSupportedCipherSuites() 动态过滤。这样升级算法时不用改客户端代码。

服务端也要配合

光客户端禁用没用,服务端也得同步。以 Nginx 为例:

ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers on;

这里有个细节:ssl_prefer_server_ciphers on 表示服务端优先选择自己的套件列表。为什么要这么做?因为有些客户端会优先选不安全的套件。服务端强制一下,能避免很多问题。

密码套件选择的核心逻辑

为了让你更直观地理解,我画了一张流程图:

密码套件选择决策流程 开始选择密码套件 检查密钥交换算法 支持 ECDHE / DHE?→ 保留 | 否则 → 禁用 检查对称加密算法 AES-GCM / ChaCha20?→ 保留 | 否则 → 禁用 检查消息认证码 SHA-256 / SHA-384?→ 保留 | 否则 → 禁用 生成安全套件列表 快速检查清单 ✅ ECDHE / DHE ✅ AES-GCM ✅ ChaCha20-Poly1305 ✅ SHA-256 / SHA-384 —————— ❌ RC4 ❌ CBC 模式 ❌ 3DES ❌ SHA-1 ❌ 静态 DH / RSA

常见误区

最后,我总结几个容易踩的坑:

  • 误区一:套件越多越好。其实不是。套件越多,攻击面越大。只保留必要的几个就行。
  • 误区二:只看加密强度。AES-256 比 AES-128 安全?理论上是的,但实际中 AES-128 已经足够。更重要的是算法组合是否合理。
  • 误区三:忽略前向安全性。没有 PFS 的套件,一旦私钥泄露,所有历史通信都会被解密。ECDHE 是必须的。

核心要点: 选择密码套件时,记住三个原则:前向安全、认证加密、强哈希。ECDHE + AES-GCM + SHA256 是黄金组合。别贪多,别图省事。

好了,关于密码套件的选择就聊到这里。配置好之后,记得用 sslyzetestssl.sh 扫一遍,看看有没有遗漏的不安全套件。安全这件事,多检查一遍总没错。