3. 服务端加固:禁用弱密码套件、配置TLS 1.2/1.3、HSTS配置、OCSP Stapling
服务端加固,说白了就是把你服务器上那些不安全的「门锁」全换掉,只留下最结实的那几把。我见过太多公司,TLS 证书买的是贵的,但配置却用的是十年前的标准——这就像给防弹门配了个塑料锁芯,毫无意义。
这一节,我们聚焦四个核心动作:禁用弱密码套件、强制 TLS 1.2/1.3、配置 HSTS、开启 OCSP Stapling。做完这四步,你的服务端才算真正「硬」起来。
3.1 禁用弱密码套件:别给攻击者留后门
密码套件(Cipher Suite)决定了数据怎么加密、怎么握手。但有些老旧的套件,比如 RC4、3DES、CBC 模式的某些变种,已经被证明有严重漏洞。
我个人习惯,直接用一个「黑名单 + 白名单」的思路来清理:
- 黑名单(必须禁用):RC4、3DES、IDEA、SEED、NULL 加密、EXPORT 级别套件、所有基于 MD5 的套件。
- 白名单(只保留这些):TLS_AES_128_GCM_SHA256、TLS_AES_256_GCM_SHA384(TLS 1.3 专属)、ECDHE-RSA-AES128-GCM-SHA256、ECDHE-RSA-AES256-GCM-SHA384。
核心原则:优先使用 AEAD(认证加密关联数据)模式的套件,比如 GCM。它们同时保证机密性和完整性,性能还更好。
我在项目中遇到过一家金融客户,他们的 OpenSSL 配置里还开着 DHE-RSA-AES256-SHA。这个套件用的是 CBC 模式,理论上存在 Lucky13 攻击的风险。虽然实际利用难度高,但合规审计就是过不去。我们直接把它从配置里删掉,审计一次通过。
Nginx 下的配置示例:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
注意 ssl_prefer_server_ciphers on 这个开关。它让服务器决定用哪个套件,而不是让客户端挑。你想想看,如果让客户端挑,万一它是个老旧的 IE 浏览器,可能会选一个 RC4 回来——那你的加固就白做了。
3.2 配置 TLS 1.2/1.3:砍掉旧协议
TLS 1.0 和 1.1 已经被 RFC 8996 正式废弃。SSL 2.0/3.0 更是早该入土。现在业界标准是 TLS 1.2 起步,TLS 1.3 优先。
为什么 TLS 1.3 更好?因为它把握手从 2-RTT 降到了 1-RTT,甚至 0-RTT(重连时)。而且它砍掉了所有不安全的密钥交换算法,只保留 PFS(完美前向保密)的套件。
| 协议版本 | 状态 | 建议 |
|---|---|---|
| SSL 2.0 / 3.0 | 已废弃 | 立即禁用 |
| TLS 1.0 / 1.1 | 已废弃 | 立即禁用 |
| TLS 1.2 | 当前标准 | 必须启用 |
| TLS 1.3 | 最新标准 | 强烈建议启用 |
配置很简单,但有一个坑:不要只开 TLS 1.3。因为很多客户端(比如 Android 7 以下、Windows 7 上的 IE)还不支持它。你至少要保留 TLS 1.2 作为兜底。
注意:如果你只开 TLS 1.3,大约会有 5%-10% 的客户端连不上。我建议你通过日志分析一下用户设备的分布,再决定是否彻底关闭 TLS 1.2。
我曾经帮一个电商平台做加固,他们直接一刀切只开 TLS 1.3。结果第二天客服电话被打爆——很多用旧手机的用户无法支付。后来我们改回 TLS 1.2 + 1.3,问题解决。
3.3 HSTS 配置:强制 HTTPS,不留降级机会
HSTS(HTTP Strict Transport Security)的作用,就是告诉浏览器:「以后只准用 HTTPS 访问我,别想用 HTTP 降级。」
没有 HSTS 的时候,即使用户在地址栏输入 https://example.com,第一次请求还是可能通过 HTTP 发出(比如用户手动输入 example.com)。攻击者可以拦截这个请求,做一个中间人攻击。
HSTS 的配置就是一个响应头:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
参数说明:
- max-age:单位秒。31536000 就是一年。我个人建议至少设半年(15768000),稳妥起见设一年。
- includeSubDomains:所有子域名也强制 HTTPS。如果你有
api.example.com、blog.example.com,它们也会被保护。 - preload:申请加入浏览器内置的 HSTS 预加载列表。一旦加入,即使用户第一次访问,浏览器也直接走 HTTPS。
小技巧:在 Nginx 里配置 HSTS,记得先确认你的所有子域名都支持 HTTPS。否则 includeSubDomains 会把那些不支持 HTTPS 的子域名也锁死,用户就访问不了了。
嗯,这里要注意:HSTS 的 preload 一旦提交,很难撤回。我见过一个团队,没检查清楚就把 preload 加上了,结果有个老旧的子域名只支持 HTTP,直接瘫痪。所以,先不加 preload,跑一段时间确认没问题再说。
3.4 OCSP Stapling:让证书状态查询更快、更安全
OCSP(在线证书状态协议)是用来查询证书是否被吊销的。传统方式是浏览器自己去 CA 的 OCSP 服务器查——这有两个问题:
- 慢:每次连接都要多一次 HTTP 请求。
- 不安全:攻击者可以拦截 OCSP 请求,返回「证书有效」的假响应。
OCSP Stapling 解决了这个问题。服务器在握手时,自己先去 CA 查询证书状态,然后把结果「钉」在握手包里发给客户端。客户端不用再查了,直接信任这个结果。
配置起来也不复杂,Nginx 下:
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
这里 ssl_trusted_certificate 要填完整的证书链,包括中间证书。否则 Nginx 无法验证 OCSP 响应是否来自可信的 CA。
验证是否生效:用 OpenSSL 命令行测试:openssl s_client -connect yourdomain.com:443 -status -tlsextdebug。如果输出里有 OCSP Response Status: successful,说明 Stapling 生效了。
我在项目中遇到过一个问题:OCSP Stapling 配置好了,但偶尔会失效。查了半天,发现是 resolver 超时设置太短。CA 的 OCSP 服务器有时候响应慢,5 秒不够。我改成 10 秒后,问题消失。
3.5 整体加固流程一览
为了让你更直观地理解这四个步骤的关系,我画了一张流程图:
这四步做完,你的服务端 TLS 加固就基本到位了。但别忘了,加固不是一次性工作。密码学在演进,新的攻击手法也在出现。我建议你每半年重新审视一次配置,看看有没有新的弱套件需要禁用,有没有新的协议版本需要支持。
嗯,最后说一句:配置完一定要用 SSL Labs 或 testssl.sh 扫一遍。我每次改完配置,都会跑一遍测试,拿到 A+ 评级才算完。别偷懒,这一步能帮你发现很多自己没注意到的细节。