2.2 TLS 1.3 与证书自动化:从握手到轮换
TLS 建立会话密钥,按选定模式认证服务端或双方,并保护后续记录。它不是“用证书公钥把 HTTP 加密”:TLS 1.3 通常用临时 (EC)DHE 建立共享秘密,证书私钥负责给握手上下文签名。
TLS 1.3 握手绑定协商结果
以下是证书认证、无客户端证书、无 HelloRetryRequest 和 early data 的简化完整握手;PSK 恢复模式的消息会不同:
ClientHello
supported_versions, cipher_suites, key_share, SNI, ALPN
↓
ServerHello + key_share
↓ 双方派生握手密钥
EncryptedExtensions
Certificate
CertificateVerify ← 服务端用证书私钥签名握手 transcript
Finished ← 证明握手密钥与 transcript 完整
↓ 客户端验证服务端
Client Finished ← 客户端确认握手 transcript
↓
后续记录使用应用流量密钥证书验证回答“这个公钥是否被信任用于目标服务名”,CertificateVerify 回答“对端是否持有对应私钥”,Finished 把此前协商内容和派生密钥绑定起来。这是该证书认证流程中的职责分工;PSK 握手可以不发送证书,而以已建立的 PSK 信任完成认证。
TLS 1.3 cipher suite 只选择 AEAD 与 hash,密钥交换和签名算法在独立扩展中协商。这与 TLS 1.2 的套件命名不同,不能用旧的字符串检查逻辑判断全部安全属性。
SNI 与 ALPN 参与服务选择
SNI 告诉共享地址上的服务端客户端要访问哪个 hostname,服务端据此选择证书和虚拟主机;ALPN 协商 HTTP/2、HTTP/1.1 等应用协议。两者配置错误会导致拿错证书、路由到错误租户或协议降级。
SNI 在传统 TLS 1.3 ClientHello 中通常可见,TLS 本身不隐藏访问的域名。需要保护这一元数据时,要关注 ECH 的实际客户端、DNS 和服务端生态支持,即使成功使用 ECH,目标 IP、流量大小和时间特征仍可能可见。SNI 参与选证书,本身不是客户端完成 hostname 验证的证据。
0-RTT 以重放风险换取延迟
恢复会话时,TLS 1.3 可以让客户端在完整握手前发送 early data。0-RTT 不具备一般意义上的重放保护,攻击者可能让服务端多次接收同一请求。
因此转账、创建订单、修改权限、发放凭据等非幂等操作不应接受 0-RTT。即使 GET 被设计为幂等,也要确认重放不会导致重复计费、一次性 token 消耗或不可接受的审计负荷;正常的重复访问日志并不自动违反 HTTP 幂等语义。防重放需要应用与 TLS 终止层共同设计,不能仅靠库开关。
mTLS 认证的是证书主体,不是业务授权
双向 TLS 中,服务端也请求客户端证书、验证其链与身份,并验证客户端的 CertificateVerify 持钥证明。它适合受控设备、服务间身份和高保证管理接口,但仍需映射:
validated certificate identity
→ workload / device principal
→ authorization policy
→ permitted resource and action“来自受信 CA 的任意证书”通常过宽。要检查 SAN/URI identity、EKU、签发层级、环境和吊销状态,并限制哪个 issuer 能为哪个命名空间发证。连接池与长连接可能继续使用早先建立的会话,不会因为磁盘证书换新就自动重验身份;必要时需要连接寿命限制、重新认证或主动关闭,纳入撤销窗口分析。
ACME 把域名控制验证变成协议
ACME 的核心对象关系:
Account → Order → Authorization → Challenge → Finalize CSR → CertificateHTTP-01、DNS-01 等 challenge 证明申请者能完成对应域名控制验证,不证明网站经营者可信、合法或没有恶意内容。DNS-01 适合通配符和不直接暴露 HTTP 的服务,但 DNS API 凭据往往权限很大;应限制到特定 zone/record、使用短期凭据并隔离签发控制器。
证书自动化不是一个 cron:
- 提前续签并加入随机抖动,避免同一时刻风暴;
- 将匹配的证书与私钥作为同一版本发布,例如先写入新目录,再切换版本指针;分别替换两个文件不等于原子发布;
- 让进程 reload 或热更新,并验证实际 listener 已加载新 serial;
- 保留短暂重叠以支持连接和多副本滚动;
- 从外部探针检查链、SAN、协议和剩余期限;
- 对签发、challenge、reload 和握手错误分别告警。
只监控磁盘上的 .pem 到期日,会漏掉负载均衡器仍在提供旧证书的情况。
检查真正提供服务的监听端口
下例要求目标已经提供 TLS 服务,并用 roots.pem 明确指定本次测试信任的根。将连接地址替换成实际测试地址;若直连某个后端 IP,仍保留要验证的服务名。
openssl s_client -connect api.example.com:443 \
-servername api.example.com -verify_hostname api.example.com \
-verify_return_error -CAfile roots.pem -tls1_3 \
-alpn h2,http/1.1 </dev/null-servername 发送 SNI,-verify_hostname 检查预期身份,-verify_return_error 让验证错误终止握手;三者不能互相替代。核对输出中的协议、协商 ALPN 与验证结果;把返回的 PEM 证书保存为 served-leaf.pem 后,可用 openssl x509 -in served-leaf.pem -noout -serial -dates 检查序列号与有效期。再把 hostname 改错,确认握手失败。强制 -tls1_3 只证明这一轮测试支持 TLS 1.3,不证明服务器已经禁用旧协议。
私有 PKI 要限制故障影响范围
服务网格或工作负载身份平台常签发数小时到数天的短期证书。短生命周期降低静态凭据长期泄露风险,却把可用性依赖转移到 issuer、身份 attestation、时钟和轮换代理。
根密钥应离线或严密保护,在线 intermediate 按环境、区域或用途隔离。轮换 CA 需要 trust bundle 先加入新根、再迁移签发层与叶子、等待旧凭据和会话退出后移除旧根的重叠阶段;直接替换根会把整个集群切断。
TLS 生产基线
- 优先 TLS 1.3;需要 TLS 1.2 兼容时按 BCP 195 限制协议与套件;
- 禁用证书校验失败后的默认继续路径;
- 使用提供前向保密的密钥交换并安全管理 session ticket key;
- 明确是否启用 0-RTT,以及哪些请求可以接受;
- 对外部与内部服务都验证完整链、reference identity 和用途;
- 自动签发、续期、部署、reload 与外部验证连成可复验流程;
- 监控握手失败率、协议版本、证书剩余期限和异常新证书。
下一章从服务身份转向用户认证与会话,再学习 OAuth/OIDC 和授权策略。