2.4 HTTPS 与证书:全站加密
场景:证书过期之夜
如果说网关建设里哪件事最不该出但偏偏出了,那就是证书过期。某个周六晚上十一点,群里有客户问接口是不是挂了,值班同事一看监控全是 TLS 握手失败——网关的域名证书当天到期。我们买的是一年期证书,没人设提醒,到期即停服。全员折腾到凌晨三点才换好新证书。第二天复盘会上立下军令状:所有证书集中托管加自动告警,缺一天都不行。
这件事之外,我们还多做了一步:全站强制 HTTPS,任何 HTTP 请求一律 301 跳 HTTPS,杜绝明文凭据在公网裸奔。前面的签名校验防的是篡改与重放,HTTPS 防的是窃听,两者缺一不可,少了任何一层,另一层的防线都会被绕过。
方案:证书托管与加密套件
证书方案我们对比了三条路。第一是手动申请免费证书,一年期,需要人工记得换,出局——那次事故就是这么来的。第二是付费买多年期证书,贵,但依然没有告警兜底。第三是腾讯云 SSL 证书服务加 CDN/负载均衡侧托管,证书由平台统一管理与提醒,续期在控制台点一下,监控里还能看到到期天数。我们选了第三条:
| 方案 | 成本 | 到期告警 | 最终选择 |
|---|---|---|---|
| 手动免费证书 | 零 | 全靠人记 | 出局 |
| 多年期付费证书 | 高 | 无 | 备用 |
| 云 SSL 托管 | 低 | 平台自动告警 | 采用 |
加密套件方面,Nginx 只保留 TLS 1.2 与 1.3,1.0 与 1.1 直接关掉。虽然牺牲了极少数古董客户端,但安全收益大于一切。HTTP/2 顺手开启,多路复用对高并发小响应特别友好。
从成本角度也值得一提。开启 HTTP/2 与长连接复用之后,TLS 握手次数大幅下降,CLB 与网关的 CPU 占用降了约三成,相当于省了一台机器的钱。加密不是纯支出,配置得当的加密反而能摊薄整体成本,这条经验后来写进了公司的技术规范第一条。
配置:Nginx 全站 HTTPS
配置部分每行都来自实战。HSTS 头是一次性把后续请求全锁定 HTTPS 的关键,加上之后客户端会记住一年;OCSP 装订减少握手延迟;加密套件只留高强度组合:
server {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri; # 强制跳转
}
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_certificate /etc/tls/fullchain.pem;
ssl_certificate_key /etc/tls/privkey.pem;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security
"max-age=31536000" always;
location / { proxy_pass http://127.0.0.1:9000; }
}
证书巡检清单
那次事故之后我们建立了每周巡检,五个检查项固定锚定在每周三上午十点,跑脚本出一页报告,异常直接发群。清单看起来朴素,但证书这种东西就是靠纪律而非智商守住:所有异常项都直接推送到值班群,并在工单系统生成跟踪单,直到评级恢复 A 级才允许关单:
| 频次 | 工具 | 输出 |
|---|---|---|
| 每周 | 巡检脚本 | 一页报告 |
| 每月 | 人工抽查 | 复核签字 |
| 每季 | 演练 | 模拟证书紧急替换 |
季度演练是最有价值的环节:从接到告警到 CLB 换好备用证书,我们目前的耗时是十一分钟。没有演练的话,第一次实战绝不会是这个速度。
| 检查项 | 红线 |
|---|---|
| 到期天数 | 不足 30 天 |
| 覆盖域名 | 与路由表完全一致 |
| 绑定资源 | CLB 与 CDN 全部生效 |
| 评级 | SSL 检测低于 A |
| 跳转链路 | HTTP 一律 301 到 HTTPS |
踩坑:HSTS 的双刃剑
HSTS 是双刃剑,开的第一天就有客户在公司内网代理后调接口报错(代理做了中间人解密,被 HSTS 直接拒绝)。折中方案是域名层面分开:对外的 api.example.com 开 HSTS,内网测试域名不开。第二个坑是证书链不全,只配了证书没配中间证书,导致部分手机端浏览器报证书不可信。规范做法是 fullchain 一次配全,并用公开的 SSL 检测工具跑一遍评级,目标拿到 A 及以上。
第三个坑是文档站忘了配 HTTPS。接口都加密了,文档站还是 HTTP,客户在文档页贴的密钥截图照样能被嗅探。后来文档站一起上了 HTTPS 并挂 CDN(CDN 文档入口 cloud.tencent.com/document/product/228),CDN 侧自动托管证书加速两不误,海外客户打开速度还快了三倍。
第四个坑是 TLS 握手耗时。PHP 网关到后端的调用我们也走了 HTTPS,刚上线没注意连接复用,每个请求都重新握手,高峰期 CPU 飙高。开启 guzzle 的连接池与 keep-alive 后回落。HTTPS 的成本主要在握手,长连接复用是唯一的解药。
顺带提一个内部服务的小优化。服务间调用我们后来上了 mTLS 双向认证,配合服务发现后内部链路也实现了零信任——即使某台机器被攻破,它的证书也调不通其他服务。这一层投入不大但防御纵深重要,至于是不是要在你们的场景上,看投入产出比,核心链路建议跟。
再加一段关于多域名与泛域名证书的经验。我们的网关后来扩展出了多个业务子域,最初每个子域一张证书,巡检与续期工作量线性增长。统一切到泛域名证书(一张证书覆盖 *.example.com)后管理成本骤降,配合云 SSL 托管续期几乎零操作。泛域名证书的唯一注意点是私钥泄露影响面大,所以它的轮换频率要更高,权限管制更严,仅少数运维同学可接触。选型永远在方便与风险之间找平衡点。
HTTPS 与性能的账
最后算笔性能账,给犹豫加密会拖垮性能的同学一颗定心丸。我们实测开 HTTPS 前后对比:单请求平均耗时增加约 1.5 毫秒(主要是握手与加密开销),但开启长连接复用与 HTTP/2 之后这项摊薄到 0.3 毫秒以下,而服务器 CPU 增加不到一成。相比之下,接口被中间人篡改或凭据泄露一次的代价是百万级起步。这笔账没有任何悬念,全站 HTTPS 无需犹豫。
CDN 侧(文档入口 cloud.tencent.com/document/product/228)还带了一个意外收益:CDN 节点就近终结 TLS,海外客户的首字节时间降到了本地水平,文档站的跳出率降了四成。加密与加速并不冲突,用对工具还能互相成就。
再补一个迁移期的小技巧。灰度切换 HTTPS 期间,总有少数老客户端不支持跳转(比如某些老旧嵌入式设备),对这些设备我们保留了为期三个月的明文兼容通道,但限速到每秒一次且只放白名单接口,同时 CLS 全量留痕供审计。过渡期既要往前走,也要给确实走不动的人留条路,期限公开透明,到期自然关停。灰度与兼容的艺术,说到底是时间管理:窗口给够,底线守牢。
最后给正在纠结要不要全站 HTTPS 的团队一剂强心针。我们核算过:全站 HTTPS 加证书托管加巡检的全部一次性投入约两人周,后续维护每周半小时;而一次凭据泄露事件的平均处置成本是两到三人天加客户信任折损。前者是确定性的小投入,后者是不确定性的大风险,但凡会算账的团队都知道怎么选。加密唯一真正的成本,是你以为它很贵的误解。当你的 HTTPS 也做到全自动巡检的时候,它就成了不会被想起却永远在岗的保镖。这部分投入起步早、节奏稳,后面的高可用篇会感谢你现在打下的底子。证书、跳转、巡检这套组合拳打完,接入层的最后一环也闭合了。
小结
HTTPS 这节的核心其实不是技术,是运营:证书集中托管加自动告警、HSTS 开启但区分内外网、fullchain 配齐全、握手用长连接摊薄。全站加密是网关给客户的第一份承诺,自己先要做到,后来的客户信任评级里这一项加了分。又一次印证那条朴素的经验:安全不是一次配置,是一套持续运行的流程。巡检清单坚持到今天两年多,再没让客户提醒过我们证书的事。
再送一句给小团队的话:没有预算上云 SSL 托管,就用免费的证书加一个 cron 每天扫描到期天数,提前三十天发企业微信告警。零成本也能跑通自动提醒,缺的从来不是工具,是把证书当回事的态度。
还有一个免费的红利:把 HTTPS 与 HTTP/2 一起开启。网关是长连接密集型场景,HTTP/2 的多路复用让我们的连接数降了四成,握手开销摊薄后 P99 还稳了一截。做法是在 Nginx 层终结 HTTP/2,后端仍走 HTTP/1.1,几乎零成本拿到收益。
