第3章 TLS/SSL协议:握手、验证与双向认证

做API网关层加密,TLS/SSL是躲不开的基本功。你可能觉得它就是个“加个https”,但实际集成时坑不少。这一章我们拆开揉碎讲。

3.1 TLS 1.3 握手——少了两轮,快了一截

我最早做网关加密时还在用TLS 1.2,那会儿握手要2-RTT才能拿到会话密钥。后来升级到1.3,减到1-RTT,甚至0-RTT(需谨慎)。

TLS 1.3握手核心步骤:

  1. ClientHello:客户端发送支持的密码套件、随机数、以及一个可通过DH或ECDH计算的密钥共享参数(Key Share)。
  2. ServerHello + 证书 + 签名:服务器选出密码套件,返回自己的密钥共享参数,同时带上证书链和数字签名。这一步就已经算出主密钥。
  3. 结束消息:双方派生出加密密钥,后面的应用数据直接加密传输。

小提示:TLS 1.3废弃了RSA密钥交换(因为不支持前向安全性),只保留ECDHE和DHE。我个人习惯用X25519曲线,性能好且安全。

对比1.2,1.3还移除了很多不安全的密码套件。GC错CBC模式、RC4这些老古董都被砍掉了。

注意:0-RTT模式下存在重放攻击风险。我曾经在一个支付网关项目里开了0-RTT,结果发现重放攻击测试部分失败。后来我们只在查询接口用0-RTT,写入接口老老实实走完整握手。

3.2 证书链验证——信任的传送带

公钥证书是TLS的信任基石。但客户端怎么知道服务器给的证书靠谱?靠证书链。

一个完整的证书链长这样:

  • 叶子证书:由CA签发给你的网站(或API域)。
  • 中间CA证书:用来签发叶子证书,避免根CA私钥被直接暴露。
  • 根CA证书:预装在操作系统或浏览器里(比如IdenTrust、DigiCert的根)。

验证流程:

  1. 客户端从叶子证书开始,用上层证书的公钥验下层的签名。
  2. 一层层向上,直到自签名的根CA证书。
  3. 检查证书有效期、是否被吊销(CRL/OCSP),以及域名是否匹配。

我踩过的坑:有一次用户说“我的API访问报TLS错误”,我查了半天发现是他们用了自签名证书,但没有在客户端信任列表中加载根证书。其实证书链验证很简单:任何一个环节不信任,整个握手就断掉。

证书链验证还有一个细节:路径长度限制。根CA可以限制中间CA最多签发几级子CA。如果在证书里看到pathLenConstraint:0,意味着这个中间CA只能签发叶子证书,不能再签发下级CA。

3.3 双向认证(mTLS)——不只是验证服务端

常规TLS只验证服务器。mTLS要求客户端也提供证书,服务端验证客户端的身份。在微服务架构里,这东西特别有用。

握手流程多两步:

  1. 服务端在ServerHello之后,发送 CertificateRequest。
  2. 客户端收到后,发送自己的证书链,并做一次签名验证。

配置关键点:

环节 传统TLS mTLS
服务端证书 必须 必须
客户端证书 不要求 必须
验证方向 单向 双向
应用场景 公网用户访问 内部服务/设备通信
证书管理复杂 低 高(需给每个客户端签发)

举个例子,Nginx启用mTLS:

server {
    listen 443 ssl;
    ssl_certificate     /etc/certs/server.crt;
    ssl_certificate_key /etc/certs/server.key;
    ssl_client_certificate /etc/certs/ca.crt;  # 用于验证客户端
    ssl_verify_client on;
    ssl_verify_depth 2;

注意 ssl_verify_client on 开启验证,ssl_verify_depth 控制证书链深度。我一般设为2或3,防止有中间CA层级太多导致验不过。

避坑提醒:我曾经在kubernetes里配mTLS时,没注意Ingress Controller的证书目录权限,结果Pod启动后找不到私钥。后来我统一用Secret挂载,权限设为600,就再没出过问题。

3.4 本章知识结构

TLS 1.3 握手与证书验证流程 TLS 1.3 握手与证书验证流程图 Client ClientHello + KeyShare ServerHello + Cert + Sig 证书链验证 切换密钥 → 结束消息 加密数据通信 mTLS 额外步骤: Server 发送 CertificateRequest Client 发送自己的证书链 + 签名

3.5 实战建议与避坑

  • 证书轮换:最好在证书到期前30天自动轮换,别等告警。我习惯用ACM或者cert-manager做自动化。
  • 密码套件:只保留TLS_AES_128_GCM_SHA256和TLS_AES_256_GCM_SHA384。CHACHA20_POLY1305在移动端确实有优势,但服务端用AES-GCM通常更快。
  • 禁止弱协议:网关侧强制只开启TLS 1.2和1.3,最好直接砍掉TLS 1.0/1.1和SSL。

核心总结:TLS 1.3让握手更快、更安全;证书链验证是信任基石;mTLS让服务间通信更可信。这三样东西在网关层加密中缺一不可。