5.1 TLS 握手、证书链与安全边界
TLS 建立的安全通道要回答三个问题:
- 路径上的观察者能否读懂内容?
- 内容被修改时,接收方能否发现?
- 对端是否真是客户端打算连接的身份?
TLS 分别用 confidentiality、integrity 和 peer authentication 回答它们。HTTPS 通常是 HTTP over TLS;“SSL”只是许多 API 中保留的历史名字,现代部署不应启用 SSLv2 或 SSLv3。
1. TLS 在协议栈的位置
对 HTTP/1.1 和 HTTP/2 而言,常见路径是:
HTTP semantics
↓
HTTP/1.1 message framing 或 HTTP/2 frames
↓
TLS records
↓
TCP byte streamTLS 不是 OSI 模型里只能归入某一层的固定答案,实践中把它看成 application protocol 与 transport 之间的安全层就够了。HTTP/3 的路径不同:QUIC 集成 TLS 1.3 handshake,使用 QUIC packet protection,不采用 TLS record layer。
2. 先看 TLS 1.3 的主线
下图限定为证书认证的完整握手,没有 HelloRetryRequest、PSK 恢复或 client certificate。ALPN 的最终选择在 EncryptedExtensions 中,ServerHello 本身不返回整个协商结果。
Client Server
| |
| ClientHello |
| supported_versions, key_share, SNI, ALPN ------>|
| |
|<------ ServerHello, key_share |
| {EncryptedExtensions} |
| {Certificate} |
| {CertificateVerify} |
| {Finished} |
| |
| {Finished} ------------------------------------->|
| |
|<========== protected application data ==========>|花括号里的 message 已经受 handshake traffic key 保护。这是 TLS 1.3 的重要变化:ServerHello 之后的大部分 handshake 不再明文暴露。
ClientHello 带了什么
supported_versions:客户端真正支持的 TLS 版本;key_share:临时 (EC)DHE 公开参数;- SNI:希望访问的服务名,便于一个 IP 选对证书;
- ALPN:希望在 TLS 里使用
h2还是http/1.1等 application protocol。
ServerHello 选定版本、cipher suite 和 key share。双方根据 ephemeral Diffie–Hellman shared secret 和 handshake transcript 派生 key;临时私钥不是服务器 certificate private key。
可以用一个很小的 Diffie–Hellman 算例看共享值怎样相同:
p, g = 23, 5
alice_private, bob_private = 6, 15
alice_public = pow(g, alice_private, p)
bob_public = pow(g, bob_private, p)
alice_shared = pow(bob_public, alice_private, p)
bob_shared = pow(alice_public, bob_private, p)
assert alice_shared == bob_shared == 2
print(alice_public, bob_public, alice_shared) # 8 19 2这里的 23 只方便手算,暴力枚举即可破解,不能用于加密。真正的 TLS 使用标准化 group,并经 HKDF 和 transcript 派生不同用途的密钥;这个算例本身也没有身份认证,仍可被中间人替换公开参数。
身份证明与 Finished
Certificate 给出 server 为这次连接选择的 certificate chain。CertificateVerify 用 certificate private key 对 handshake context 签名,证明对端确实持有相应 private key。Finished 对 transcript 做 key-based verification,让双方检测 handshake 是否被篡改。
一次完整的 TLS 1.3 handshake 通常用 1 RTT 建立 application traffic keys。这不等于“打开网页只要 1 RTT”:DNS、TCP 或 QUIC 建连、HTTP redirect 和 resource loading 都可能增加往返。
如果 key share 不符合服务器要求,HelloRetryRequest 会增加一轮;恢复握手可能省略 Certificate/CertificateVerify,并依据 PSK 建立认证状态。也不能把图理解为服务器必须等客户端 Finished 才能发送任何应用数据,双方可用数据的时机应按具体握手状态判断。
3. Certificate path validation 不是“对上签名”就结束
local trust anchor
|
intermediate CA certificate
|
leaf certificate for service identityServer 通常发 leaf 和所需 intermediate certificates,不应把 root 当作必须发送的链尾。最后的 trust anchor 由 client 的 trust store 和 policy 决定;它不是因为“自签名”就自动可信。
通过 certificate path validation 只是验证的一部分。HTTPS client 至少还要检查:
- certificate 的 validity period 覆盖当前时间;
- subjectAltName 中的标识与期望 service identity 匹配;
- key usage / extended key usage 允许它用于对应用途;
- signature algorithm、key size 和 policy 可接受;
- certificate 没有被 local policy 判定为 revoked。
这也是为什么不应在业务代码里自己实现 certificate validation。使用成熟 TLS library 的 secure defaults,再明确配置 trust store 和 service identity。
例如证书只有 DNS SAN *.example.test,它可覆盖 api.example.test,不能覆盖 example.test 或 a.b.example.test。访问 IP literal 时需匹配 IP SAN,不能把 DNS SAN 中看似 IP 的字符串当成同一种标识。RFC 9525 不再接受用 subject Common Name 代替 SAN。
4. Cipher suite 到底协商了什么
TLS 1.2 的一个 suite 名可能包含 key exchange、authentication、bulk encryption 和 hash,例如 IANA 名称:
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
| | | |
key ex auth AEAD PRF hashOpenSSL 也常把它显示为 ECDHE-RSA-AES128-GCM-SHA256。两种字符串不同,不代表协议不同。
TLS 1.3 的 suite 缩小了职责:
TLS_AES_128_GCM_SHA256它选择 AEAD 和 HKDF 使用的 hash。Key exchange group 与 signature algorithm 在其他 extension 中独立协商。因此,不能从 TLS 1.3 suite 名里推断 server certificate 是 RSA 还是 ECDSA。
5. Forward secrecy 保护的是过去
旧式 static RSA key exchange 中,如果攻击者录下 encrypted traffic,以后又拿到 server private key,就可能恢复过去的 session secret。Ephemeral (EC)DHE 为每次 handshake 产生临时 key material;长期 private key 用于 authentication,不直接变成 application traffic key。
这叫 forward secrecy。它假定 ephemeral secret 已及时销毁,也不会神奇地抵消 endpoint 当时已被控制的风险。TLS 1.3 的 certificate-based full handshake 使用 ephemeral (EC)DHE,不再支持 TLS 1.2 的 static RSA key exchange。
这个结论针对包含临时 (EC)DHE 的握手。TLS 1.3 也定义仅基于 PSK 的模式,不能把“版本是 1.3”直接等同于每种模式都具有相同的 forward secrecy。
6. 0-RTT 不是免费的加速
TLS 1.3 在会话恢复时允许 client 发 early data,但 early data 可被 replay,它的 security properties 也与普通 application data 不同。
所以不要把“支付”“创建订单”“发放奖励”这类 non-idempotent operation 无条件放进 0-RTT。Server 要明确决定是否接收 early data,application 也要有 replay defense。
0-RTT 数据本身也不具备普通握手后数据相同的 forward secrecy。即使方法名叫 GET,若 endpoint 实际会产生副作用,或重放会产生不可接受的额外业务效果,也不能仅凭 Safe/Idempotent 标签放行;HTTP 服务可按 RFC 8470 用 425 Too Early 要求在握手后重试。
7. TLS 不解决什么
- certificate 通常验证 service identity,不验证登录用户的业务权限;
- endpoint 中毒时,plaintext 在加密前或解密后仍可被偷走;
- TLS 不防 SQL injection、XSS、CSRF 或越权;
- 对端 IP、traffic timing 和 volume 等 metadata 仍可观测;SNI 是否隐藏取决于 ECH 部署,不能默认已隐藏;
- TLS 不保证 service availability。
8. 常见误解
“有锁图标就说明网站可信。” 它只说明 browser 成功建立了与该 service identity 的 protected connection,不代表这家站点的商业行为值得信任。
“Server 发来的 root certificate 证明了自己。” Trust 来自 client 预先配置的 trust anchor 和 policy,不来自对端自己递上来的 root。
“TLS 1.3 的 AES suite 说明 certificate 一定是 RSA。” TLS 1.3 把 AEAD suite 与 signature algorithm 分开协商。
“把 certificate verification 关掉,content 还是 encrypted,所以可以上线。” Encryption 没有 authentication 时,client 可能正在和 attacker 建立一条完美加密的通道。
9. 练习与验收
- 按顺序说出 TLS 1.3 中
Certificate、CertificateVerify和Finished各自证明了什么。 - 为什么 server private key 泄露不一定能解开过去录下的 TLS 1.3 full-handshake traffic?
- 用自己的话区分“certificate path valid”和“service identity matches”。
- 列出两个不应无条件放入 0-RTT 的 operation,说明共同原因。
实际故障往往只返回 CERTIFICATE_VERIFY_FAILED,不会直接说明是缺 intermediate、名称不匹配还是时间错误。下一课进入5.2 TLS 安全客户端与故障诊断,把这些原因逐项分开。