前十八章的每一块积木,都在一次 HTTPS 握手里各就各位。这是理论汇成工程的地方。
你的 App 每次发起 HTTPS 请求,背后都在几十毫秒内跑完一整套密码学协议。它把密钥交换、签名、证书、AEAD 全都拼在一起——而每一块你现在都认识了。这一章我们把 TLS 1.3 的握手逐条消息拆开,你会惊讶地发现:没有任何新东西,全是老朋友。
TLS(传输层安全,HTTPS 里的 "S")要在一条不可信的网络上,同时达成:
bank.com,不是中间人(第 18 章的证书/信任链)。注意这正是第 15、18 章反复强调的那条接缝:密钥协商 + 身份认证必须同时做对,否则中间人就钻进来了。TLS 的握手,本质就是把这两件事严丝合缝地缝在一起。
下面的动画一步步展开 TLS 1.3 握手。每条消息旁边标注了它用到哪一章的知识。点"下一步",看会话密钥如何从无到有,以及加密从第几条消息开始生效。
| 握手环节 | 用到的密码学 | 对应章节 |
|---|---|---|
| 协商临时密钥 | ECDHE(临时椭圆曲线 DH) | 第 15、17 章 |
| 前向保密 | 每次会话用一次性 DH 私钥 | 第 15 章 |
| 服务器身份认证 | 证书 + 签名 + CA 信任链 | 第 18 章 |
| 从共享密钥派生会话密钥 | HKDF(基于 HMAC 的 KDF) | 第 12、13 章 |
| 加密应用数据 | AES-GCM 或 ChaCha20-Poly1305 | 第 9 章 |
| 握手完整性(Finished) | 对整个握手记录做 MAC | 第 12 章 |
看这张表——TLS 没有发明任何新密码学。它是一套精心设计的编排,把你已经学过的原语按正确顺序、以正确方式组合起来。密码学工程的难点从来不是原语,而是这种组合的正确性:消息顺序、状态机、降级防护、错误处理,任何一处接缝出问题,整个安全性就崩了。
TLS 1.3(2018)相比 1.2 最大的改进,是砍掉了所有危险的选项:去掉了 RC4(第 6 章)、去掉了 CBC 模式的 MAC-then-Encrypt(padding oracle 的温床,第 8 章)、去掉了静态 RSA 密钥交换(没有前向保密)、强制所有密码套件都用 AEAD 和临时密钥交换。历史上 TLS 的大多数漏洞(BEAST、CRIME、POODLE、Lucky13……)都源于"为了兼容而保留的旧选项"。1.3 的哲学和本书一致:把容易用错的东西从系统里删掉,比寄望每个人都配置正确更可靠。
TLS 1.3 强制前向保密(第 15 章)。它的意义值得再强调:每次会话的 DH 私钥都是临时生成、用完即弃的。这意味着——即使多年后攻击者攻破了服务器、拿到了它的长期私钥,他也无法解密之前录下的任何历史流量,因为那些会话密钥早已随临时私钥一起消失了。
对比一下:老式的静态 RSA 密钥交换里,所有会话都用服务器那一把长期密钥加密。一旦这把密钥泄露,攻击者能把过去所有录下的流量一次性解密。前向保密把"一次泄露、全盘皆输"变成了"一次泄露、只影响当下"。这也是第 25 章 Signal 双棘轮要把这个思想推到极致的原因。
好消息:Android 的 OkHttp / HttpsURLConnection 底层的 Conscrypt 已经把 TLS 做得又对又好,默认配置就是安全的。你不该做的事反而更重要:
· 别自定义 TrustManager 去"信任所有证书"(checkServerTrusted 留空)——这是最常见的、直接让 MITM 畅通无阻的致命错误,应用商店会因此拒审。
· 别为了"抓包方便"在生产版里关掉证书校验。
· 别用已废弃的 SSLv3/TLS 1.0。
真正需要你介入的,是加强而非削弱:证书固定(pinning)、以及用 Keystore 保护本地密钥。这两件事正是接下来两章的内容。
TLS 保护了 App 到服务器这段"在路上"的数据。但数据"落地"到设备之后呢——你的密钥、token、用户凭证,存在手机的哪里、怎么存才安全?这就轮到 Android 平台自己的密码学设施登场了。下一章,我们钻进 Keystore。