CDN SSL/TLS 配置最佳实践:保障传输安全与性能
CDN 承载 HTTPS 流量时,SSL/TLS 配置直接决定两件事:数据在边缘节点和用户之间安不安全,以及握手环节要花几个网络往返。这两件事经常被当成"要么选安全、要么选快"的单选题,但实际上,一份优化的 TLS 配置可以同时把两者做好——关键是证书、协议版本、密码套件、会话复用这几块分别下功夫。
一、证书选择与部署
1.1 证书类型怎么选
| 证书类型 | 适用场景 | 验证级别 | 成本 |
|---|---|---|---|
| DV(域名验证) | 个人/小型网站 | 低 | 免费-低 |
| OV(组织验证) | 企业网站 | 中 | 中 |
| EV(扩展验证) | 金融/电商 | 高 | 高 |
| 通配符证书 | 多子域名 | 按级别 | 中-高 |
对绝大多数内容型网站,DV 证书足够。地址栏的小锁和"浏览器报不安全"的差距,DV 和 EV 都能解决;OV/EV 多的主要是企业信息展示,对转化率的影响其实很小。值得一提的是,浏览器厂商这两年陆续移除了地址栏对 EV 的绿色标识展示,EV 的"信任背书"价值进一步缩水,选型时可以更放心地先上 DV。
1.2 CDN 上的证书管理
优先用自动管理,省心且不会过期翻车:
Cloudflare: 自动 SSL
AWS CloudFront: ACM 自动续期
Azure: App Service 托管证书
阿里云: 免费 DV 证书
手动上传的话,注意把中间证书链一起上传,只传叶子证书会一路"证书链不完整",部分老客户端直接拒绝连接。
1. 在 CA 购买或生成证书
2. 上传到 CDN 控制台
3. 配置证书链(完整链)
4. 设置自动续期提醒
1.3 Let's Encrypt 集成
大部分 CDN 支持 Let's Encrypt 自动签发:
- Cloudflare:内置免费证书,自动续期
- Bunny CDN:自动 Let's Encrypt
- AWS:需 ACM 导入
参考:Let's Encrypt 文档 https://letsencrypt.org/docs/;Cloudflare SSL 指南 https://developers.cloudflare.com/ssl/
二、TLS 协议版本配置
| 协议 | 安全性 | 性能 | 推荐 |
|---|---|---|---|
| TLS 1.3 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ✓ 启用 |
| TLS 1.2 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ✓ 启用 |
| TLS 1.1 | ⭐⭐⭐ | ⭐⭐⭐ | ✗ 禁用 |
| TLS 1.0 | ⭐⭐ | ⭐⭐ | ✗ 禁用 |
| SSL 3.0 | ✗ | ⭐ | ✗ 禁用 |
TLS 1.3 最大的变化在握手:从 1-RTT 缩到 0-RTT(配合会话恢复),省掉 1-2 个往返。对移动网络这种高延迟场景,一个往返可能就是 50-100ms 的体感差异。
Cloudflare: SSL/TLS → Edge Certificates → Minimum TLS Version: 1.2
CloudFront: Security Policy → TLSv1.2_2021
Nginx + CDN: ssl_protocols TLSv1.2 TLSv1.3;
配置上从"允许 TLS 1.0"升到"最低 1.2",同时保留 1.3,是当前兼容性和安全性的平衡点。除非目标用户群里有极老的浏览器(如 Windows XP 时代的 IE),否则没有理由再开 1.0/1.1。
一个常被忽略的细节是 TLS 1.3 的 0-RTT:它省握手的同时也带来重放风险,对下单、支付这类需要幂等性的接口,建议关掉或只在 GET 上启用,别让一个被截获的请求被重复执行。
三、密码套件配置
TLS 1.3 的密码套件是强制的,不用配;要花心思的是 TLS 1.2 部分,别用默认顺序:
# TLS 1.3 密码套件(无需配置)
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
# TLS 1.2 密码套件(推荐)
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-CHACHA20-POLY1305
ECDHE-RSA-CHACHA20-POLY1305
一律优先 ECDHE(前向保密)+ GCM/ChaCha20。像 RSA 静态密钥、CBC、RC4、3DES 这些要么不支持前向保密,要么有已知攻击,直接禁用:
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
所有 RC4、3DES、CBC 模式
参考:Mozilla SSL 配置生成器 https://ssl-config.mozilla.org/;IETF TLS 1.3 RFC 8446 https://datatracker.ietf.org/doc/html/rfc8446
四、性能优化
4.1 OCSP Stapling
默认情况下,客户端拿到证书后还要自己去 CA 查一次吊销状态(OCSP),多一次请求。OCSP Stapling 让 CDN 代查并把结果"钉"在握手响应里,客户端直接省掉这一步:
# Nginx 配置
ssl_stapling on;
ssl_stapling_verify on;
4.2 会话复用
同一个用户频繁建连(比如页面里有几十个资源请求)时,会话复用能把后续握手从完整握手降级为 1-RTT 甚至 0-RTT:
# Nginx 配置
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets on;
4.3 HSTS
HSTS 告诉浏览器"以后只能走 HTTPS",从根上杜绝中间人降级攻击,顺带省掉 301 跳转那一次往返:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
参考:MDN HSTS https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
五、各 CDN 配置参考
| CDN | 证书管理 | 最低 TLS | HSTS 支持 | OCSP |
|---|---|---|---|---|
| Cloudflare | 免费自动 | 可配置 | ✓ | ✓ |
| CloudFront | ACM 免费 | 可配置 | ✓ | ✓ |
| Fastly | 需上传 | 可配置 | ✓ | ✓ |
| 阿里云 CDN | 免费/上传 | 可配置 | ✓ | ✓ |
| Bunny CDN | Let's Encrypt | TLS 1.2+ | ✓ | ✓ |
六、一个排查案例
某站点上线后 Chrome 用户秒开,但一部分老 Android WebView 用户报"连接不安全"。查日志发现这些客户端还停留在 TLS 1.0/1.1,密码套件也只认 CBC。把 CDN 最低 TLS 设为 1.2 后,这批用户全部无法访问——问题不是配置错了,而是目标用户群里确实还有老客户端。这类问题最好的预防方式是在上线前用 https://www.ssllabs.com/ 全量扫一遍,看客户端兼容矩阵里有没有你不想服务的版本。最后方案:全局最低 1.2,单独为老客户端保留一个 1.1 的源站域名白名单,过渡半年后再收紧。
16IDC 建议
- 先在测试域名上改配置,用 SSL Labs 免费测一遍再上生产。
- HSTS preload 一旦提交就"回不了头",先跑几个月
max-age=31536000(不带 preload)观察再说。 - 证书快过期时,CDN 控制台通常有告警;把续期提醒同时发到邮箱和 Slack,双保险。
- 用 sslscan 或 cipherscan 定期检查线上证书与套件,配合 CDN 的版本升级计划一起做,别等出了漏洞才想起来。