Appearance
TLS 1.2、ECDHE 密钥协商与 CA 信任链
回到总览:00 基础知识(Foundations)相关模块:09. 现代移动端网络底座:HTTP/1.1、HTTP/2、HTTP/3(QUIC) 与弱网治理 · 加密与加固逆向:AES-GCM、代码混淆、Root 检测与 Frida
一句话定义
TLS(Transport Layer Security)是在不可信网络上建立加密 + 身份认证 + 完整性通道的协议;在本模块语境下,重点是 TLS 1.2 握手如何用 ECDHE 完成前向安全的密钥协商,以及客户端如何沿着「叶子证书 → 中间证书 → 根 CA」的信任链完成身份认证——它是 HTTPS / gRPC / mTLS 全部上层通信的安全底座。
代码索引
对应 Lab:TLS 1.2 ECDHE 握手与 CA 信任链验证 — 用
openssl s_client -tls1_2抓握手过程,观察 ServerKeyExchange 与 CipherSuite 协商;亦可node ecdhe-forward-secrecy.mjs离线演示前向安全
为什么需要
- 为什么明文 HTTP 在公网会被轻易窃听与篡改,而 HTTPS 不会?
- 一句话答:HTTPS 在 TCP 之上叠加 TLS,用非对称协商出一把对称会话密钥加密全量应用数据,且用证书链验证对端身份,窃听者拿不到密钥、篡改也会被 MAC/Tag 拒绝。
- 为什么很多资料强调「用 ECDHE 而不是纯 RSA 密钥交换」?
- 一句话答:纯 RSA 密钥交换里会话密钥由客户端用服务器公钥加密发出,服务器私钥一旦泄露,历史流量全部可被解密;ECDHE 是临时(ephemeral) 协商,每次连接换一对临时椭圆曲线密钥,提供前向安全(Forward Secrecy) ,服务器长期私钥泄露也不影响历史会话。
- 为什么浏览器/系统有时报「您的连接不是私密连接」,即使证书没过期?
- 一句话答:证书校验是整条链的工程:除了有效期,还要校验域名 SAN 匹配、签发链完整(中间证书不能缺)、根 CA 在信任库、未被吊销(OCSP/CRL) ;任一环节失败都会中断握手。
底层机制
1. TLS 1.2 握手主干(ECDHE + RSA 签名)
ECDHE 握手里,服务器用自己长期 RSA(或 ECDSA)证书对「临时公钥参数」做签名,既完成了身份认证,又让密钥协商材料具备前向安全:
- 可能输出(用
openssl s_client观察)Cipher Suite: ECDHE-RSA-AES128-GCM-SHA256 Server Temp Key: ECDH, P-256, 256 bits Verify return code: 0 (ok) - 预期现象:握手前两段是明文(Hello + 证书),从
ClientKeyExchange之后所有记录均加密;Server Temp Key显示的是临时椭圆曲线密钥,而非服务器证书里的长期公钥——这正是前向安全的体现。
2. CA 信任链与证书校验
客户端不「认识」每个站点证书,而是信任一小批内置在操作系统/浏览器的根 CA(Root CA) ,由此递归验证:
- 校验四要素
- 链完整:服务器必须把「叶子 + 全部中间证书」都发过来;只发叶子而缺中间,客户端若无缓存就会校验失败。
- 签名链可信:从叶子一路向上,每一级的签名都能用上一级公钥验证,最终落到某个内置根 CA。
- 域名匹配:证书
SAN(Subject Alternative Name)必须覆盖访问的 host。 - 有效期与吊销:当前时间落在
notBefore~notAfter内,且未出现在 OCSP/CRL 吊销列表。
- 预期现象:任何一环断裂(自签名根不在信任库、中间证书缺失、SAN 不匹配、已过期/吊销)都会让握手在
CertificateVerify阶段失败,客户端抛出证书错误而非悄悄降级。
Android / Flutter / Web / Backend 对照
| 维度 | Android | iOS | Web(浏览器) | Backend |
|---|---|---|---|---|
| TLS 实现 | Conscrypt(基于 BoringSSL) | Security.framework / Network.framework | 各浏览器内置 | OpenSSL / BoringSSL / Go crypto/tls |
| 信任库 | 系统 + 网络安全性配置(network_security_config.xml 可加自定义 CA) | 系统 Keychain 信任库;ATS 默认强制 TLS 1.2+ | 内置根 CA 池 | 自管理 CA 包 |
| 抓包/中间人 | 需把代理 CA 装进用户/系统信任库并配置允许 | 需安装描述文件并信任 | 浏览器手动信任代理 CA | 服务端 mTLS 双向校验 |
| 典型约束 | 7.0+ 默认不信任用户 CA,除非显式配置 | ATS 强制前向安全套件 | HSTS / 证书透明度 | 证书钉扎(Certificate Pinning) |
常见场景
- 双向认证(mTLS) :金融/内部服务除了客户端验服务器,服务器也要求客户端证书。Android 端通常把客户端证书放进 Keystore 通过
SSLContext注入;Backend 用ssl_verify_client on;之类强制校验。 - 内网自签 CA:测试环境用自签根 CA 签发服务证书,需在客户端信任库显式加入该根(Android 网络安全性配置、后端
ca-certificates),否则校验失败。 - 抓包联调HTTPS:Charles/Fiddler 的代理 CA 必须安装并被信任,且 Android 7+ 要在
network_security_config.xml声明trust-anchors包含用户 CA,否则只看到 CONNECT 隧道。
常见误配、事故后果与排障
1. 误配:服务器只发了叶子证书,漏发中间证书
- 现象:部分客户端(尤其移动端)报证书不可信,桌面浏览器却正常——因为浏览器会缓存/补全中间证书,移动端冷启动没有。
- 排障与修法:用
openssl s_client -showcerts -connect host:443看返回了几张证书;在服务器(Nginxssl_trusted_certificate/ 负载均衡)补全中间证书链后重试。
2. 事故:用了被弃用的弱套件或旧协议(TLS 1.0/1.1、RC4、3DES、SHA-1 证书)
- 后果:被合规扫描判高危,iOS ATS / 新版 Android 直接拒绝握手,无法联网。
- 排障与修法:服务端禁用 TLS 1.0/1.1,套件只留
ECDHE-*-AES-GCM/ECDHE-*-CHACHA20,证书签名算法用 SHA-256+;客户端可用 Qualys SSL Labs 评分复核。
3. 误配:证书钉扎(Pinning)写死,证书轮换后全量无法连接
- 后果:服务器证书正常续期,但客户端钉扎的旧 SPKI 指纹不匹配,集体握手失败。
- 排障与修法:钉扎时同时预埋「当前 + 下一张备用」公钥指纹,或改为只钉根/中间 CA;证书轮换窗口内保证备用 pin 已随发版生效。
相近概念对比
| 概念 | 它解决什么 | 不解决什么 |
|---|---|---|
| RSA 密钥交换 | 简单,用服务器公钥加密会话密钥 | 无前向安全;私钥泄露历史流量可解密 |
| ECDHE 密钥交换 | 前向安全,临时密钥每次不同 | 仍需证书签名来防止中间人伪造临时公钥 |
| 证书链校验 | 回答「对面是不是它声称的站点」 | 不保证站点本身业务逻辑安全 |
| 对称加密(AES-GCM) | 会话内高效加密大量数据 | 不参与密钥如何安全协商 |
对应实验
对应 Lab:TLS 1.2 ECDHE 握手与 CA 信任链验证 — openssl s_client -tls1_2 抓握手报文,识别 CipherSuite、ServerKeyExchange 与临时密钥,验证证书链;或离线跑 node ecdhe-forward-secrecy.mjs 看 ECDHE 前向安全
复习检查题
同样是 RSA,为什么「RSA 密钥交换」不安全、而「ECDHE + RSA 签名」能提供前向安全? 答:RSA 密钥交换是用服务器长期公钥直接加密会话密钥,长期私钥一旦泄露,历史上所有截获流量都能解密;ECDHE 中服务器长期 RSA 证书只用来签名临时协商出的椭圆曲线公钥参数,真正的会话密钥来自双方临时密钥的 ECDH 运算,临时密钥用完即弃,所以长期私钥泄露也不影响历史会话——这就是前向安全。
客户端校验一张站点证书,最少要检查哪几件事?为什么只发叶子证书常常失败? 答:至少四件:链完整、签名链可信(落到内置根 CA)、SAN 域名匹配、有效期与未吊销。只发叶子证书缺少中间证书时,客户端手里只有「叶子」和「内置根」,中间这一跳断开了,无法用根公钥直接验证叶子签名(叶子是由中间签的),所以校验失败——这正是很多「浏览器能连、App 连不上」的根因。
为什么移动端抓 HTTPS 包比浏览器更麻烦? 答:因为 Android 7+ 默认不信任用户安装的 CA,iOS 也必须安装描述文件并手动信任;还要在 App 的网络安全性配置里显式声明信任用户 CA(或后端关校验),否则代理的 MITM 证书通不过校验,只能看到加密隧道。
速记
- 三件事:加密(对称 AES-GCM)+ 认证(证书链)+ 完整性(Tag/MAC)。
- 前向安全:靠 ECDHE 临时密钥,不靠服务器长期私钥;长期私钥只用来「签名」临时参数防伪造。
- 信任链:叶子 ← 中间 ← 根(根内置);漏发中间证书 = 链断 = 握手失败。
- 四校验:链完整、签名可信、SAN 匹配、未过期/未吊销。