3. TLS/SSL 协议原理:握手过程、证书链、常见漏洞
讲 API 网关加密,绕不开 TLS/SSL。很多同学觉得它就是“那串小锁图标”,但实际工作中,你遇到的绝大多数连接安全问题,根子都在握手和证书链上。我记得刚做网关那会,线上突然报大量握手超时,查了一整天——最后发现是中间人设备把证书链裁剪掉了。嗯,从那以后我再看 TLS,就不敢只看概念了。
3.1 握手过程:一笔一画都是协议
TLS 握手,说白了就是客户端和服务端在正式传数据之前,先互相打个照面、亮明身份、商量好加密方式。我用一个最简单的场景给你拆开看:
- ClientHello — 客户端发个招呼,告诉服务端它支持哪些 TLS 版本、哪些加密套件、还带一个随机数。
- ServerHello — 服务端从候选里挑一个组合,也回一个随机数。
- ServerCertificate — 服务端把自己的证书发过去(可能还带着中间 CA 证书链)。
- ServerKeyExchange — 如果需要,服务端发密钥交换参数,比如 DH 的公钥。
- ClientKeyExchange — 客户端生成预主密钥,用服务端公钥加密发过去。
- ChangeCipherSpec + Finished — 双方各自算出会话密钥,然后互相发一条“我准备好了”的消息。
openssl s_client -connect host:port -debug 看每一帧,比看抓包快多了。
这里面有一个关键点:证书链验证发生在第 3 步之后。客户端收到服务端证书,必须一直追溯到信任的根证书,中间不能断。
3.2 证书链:信任靠的是层层担保
为什么要有证书链?想象一下:如果每个网站都直接找根 CA 签发证书,根 CA 得累死,而且一旦根私钥泄露,整个互联网都完蛋。所以实际结构是:
- 根证书(Root CA) — 自签名,预埋在操作系统或浏览器里。
- 中间证书(Intermediate CA) — 由根证书签发,可以有多级。
- 服务器证书(Leaf) — 由中间 CA 签发,绑在具体的域名或 IP 上。
客户端验证时,从叶子证书开始,逐级向上找签发者,直到碰到一个信任的根证书。这个过程叫 路径构建。
fullchain.pem,把中间证书和叶子证书一起发过去。
证书链长度也要注意。有些旧的客户端(比如 Android 4.x)不支持超过 3 级的链。我在金融项目里就因为这个被迫把中间 CA 合并成一级。
| 角色 | 签发者 | 位置 |
|---|---|---|
| 根 CA | 自己签自己 | 客户端信任存储区 |
| 中间 CA | 根 CA | 服务端证书链 + 客户端信任 |
| 服务器证书 | 中间 CA | 服务端 |
3.3 常见漏洞:你不得不防的几个老坑
TLS/SSL 协议活了几十年,漏洞史能写一本厚书。这里只挑对 API 网关影响最大的几个,我每个都遇到过。
3.3.1 POODLE(CVE-2014-3566)
攻击者利用 SSL 3.0 的 CBC 模式填充字节可预测性,逐字节猜出明文。当年这个消息一出,所有支持 SSL 3.0 的服务都得紧急下线。
ssl_protocols 里只写 TLSv1.2 TLSv1.3。
3.3.2 Heartbleed(CVE-2014-0160)
OpenSSL 1.0.1~1.0.1f 版本里 Heartbeat 扩展的重叠读取漏洞,攻击者可以在一次心跳请求中读出 64KB 服务端内存,里面可能就有私钥。那阵子我通宵给所有网关节点打补丁升级 OpenSSL。
3.3.3 BEAST(CVE-2011-3389)
针对 TLS 1.0 CBC 模式的攻击,利用 IV 可预测性破解加密流。现在 TLS 1.0 已经被大多数标准禁止了。
3.3.4 CRIME / BREACH
压缩 + 加密的组合拳:攻击者通过注入可控内容并观察压缩后长度变化,可以猜出 cookie 或 CSRF 。API 网关如果开启 HTTP 压缩,必须做好 随机化或者禁用压缩。
- CRIME(CVE-2012-4929) — 针对 TLS 压缩。
- BREACH(CVE-2013-3587) — 针对 HTTP 压缩。
修复很简单:关闭 TLS 压缩,并确认你的 API 响应里不包含敏感信息在压缩流中。
3.3.5 中间人攻击(MITM)
严格来说这不是协议漏洞,而是证书验证疏忽。最常见的是客户端没有校验证书链,或者信任了自签名证书。我在早期一个内部工具里犯过这个错——为了测试方便设了 SSL_CERT_FILE=/dev/null,结果上线忘了改回来…
3.4 一张图看透 TLS 握手
下面这张图把刚才讲的握手过程、证书链、以及常用加密套件串联起来。你可以把它当作排错时的思维原型。
3.5 网关场景下的最佳实践
最后,给平台工程同学提几个我在 API 网关 TLS 配置里反复验证过的动作:
- 最小化协议版本 — 只开 TLS 1.2 和 TLS 1.3,关掉所有低版本。
- 选择合适的加密套件 — 优先使用 AEAD 套件(如 ECDHE-RSA-AES128-GCM-SHA256),避免 CBC 模式。
- 证书链完整性 — 每次部署前用
openssl verify -CAfile trust.pem chain.pem检查一遍。 - OCSP Stapling — 服务端主动提供证书状态,减少客户端额外查询。
- HSTS 头部 — 网关响应里加
Strict-Transport-Security,强制客户端走 HTTPS。