04:CA 信任链——一张证书怎么做到让全世界都信它 大家好我是毛衣哥。上一期我们把 HTTP 扒光了这一期来看看加了锁的 HTTPS 又是怎么被一步步拧开的。准备好瓜子七步拆完。前两篇我们把 TLS 握手拆了个底朝天。但你有没有想过一个问题中间人到了第三步 Certificate 消息需要发一个假证书给客户端——什么情况下客户端会买账什么情况下会报警答案全在这个叫CA 信任链的东西里。这是 HTTPS 安全体系的基石也是中间人攻击唯一需要突破的防线。一个扎心的小实验打开你的 macOS 钥匙串访问Keychain Access搜索Charles或mitmproxy。如果你装过抓包工具你会看到一个证书——它的名字可能是 “Charles Proxy CA” 或 “mitmproxy”。位置在系统一类里。选中它右键 → 显示简介 → 信任你会看到使用此证书时始终信任这意味着什么你在告诉操作系统“这个 CA 签发的任何证书我都无条件信任。”不只是 example.com。任何域名。任何网站。任何 App。只要这个 CA 签字了你的系统就买账。你现在懂了这个权限有多可怕了吗你装的那个抓包 CA理论上可以冒充世界上任何一个 HTTPS 网站。证书签名到底是怎么工作的先讲一个最小白但最准确的理解方式。想象你是市政府。你签发身份证。你有一枚刻着市政府印章的钢印。把它按在身份证照片的角落上别人就知道这个身份证是你签发的、是真的。这叫签名。如果有人想伪造身份证他需要你的钢印。钢印只有你有藏在保险柜里。这叫私钥。别人验证身份证的时候不需要你的钢印——他们只需要在灯光下看一下钢印的印记跟记忆中你的印章形状对比一下。这叫用公钥验证签名。// 证书签名和验证伪代码 function sign_certificate(cert_data, ca_private_key): // 签发者CA用私钥签名 hash sha256(cert_data) // 先对证书内容做哈希 signature rsa_encrypt( // 用 CA 私钥加密哈希得到签名 key: ca_private_key, data: hash ) cert {data: cert_data, sig: signature} return cert function verify_certificate(cert, ca_public_key): // 验证者用 CA 公钥验证签名 hash_from_sig rsa_decrypt( // 用 CA 公钥解密签名拿到哈希 key: ca_public_key, data: cert.sig ) hash_computed sha256(cert.data) // 对证书内容重新做哈希 if hash_from_sig hash_computed: return VALID // 一致——证书合法 else: return INVALID // 不一致——被篡改或伪造 // 证书链验证 function verify_cert_chain(server_cert, intermediate_cert, root_cert): // 从叶子到根逐级验证 if not verify_certificate(server_cert, intermediate_cert.public_key): return FAIL // 叶子证书被篡改 if not verify_certificate(intermediate_cert, root_cert.public_key): return FAIL // 中间证书被篡改 // 根证书预装在系统里不需要验证 return PASS这个机制的关键在哪里只要 CA 的私钥不泄露任何人都无法伪造这个 CA 签发的证书。因为伪造需要私钥去签名而私钥只有 CA 有。这就是为什么中间人不能自己签发 example.com 的证书——它没有真正的 CA 的私钥。它只能用自己安装的那个抓包 CA的私钥去签。而那个抓包 CA是你亲手装到系统里的。为什么要有三级结构一个问题为什么不直接用根证书签网站证书为什么要搞出根 CA → 中间 CA → 网站证书这么复杂的三级结构答案很简单安全隔离。根证书的私钥太重要了。想象一下如果 VeriSign 的根证书私钥泄露了——攻击者可以用它签发任何域名的假证书。全世界的浏览器都会信任这些假证书。那互联网的安全基础就崩塌了。所以根 CA 的私钥是怎么保护的放在离线保险柜里。字面意思。物理保险柜。不联网。不接入任何计算机。签发中间证书的时候由人工把根证书拿出来插到一台不联网的专用设备上签名签完立刻收回去。根 CA 只做一件事给中间 CA 签名。中间 CA 才是真正给你签发网站证书的。如果某个中间 CA 被黑了怎么办吊销它的权限。根 CA 可以在根证书层面撤销对那个中间 CA 的信任。不影响根 CA 自身的安全。这就是分权。整个链条长这样根 CA预装在你的操作系统里 └→ 用根 CA 私钥签名 → 中间 CA 的证书 └→ 用中间 CA 私钥签名 → 你的网站证书example.com验证的时候反过来收到 example.com 证书 → 看 Issuer 字段签发者是中间 CA → 检查系统里有没有信任中间 CA → 没有但 Issuer 的 Issuer 是根 CA系统里有 → 用根 CA 的公钥验证中间 CA 的签名 → 合法 → 现在信任中间 CA 了 → 用中间 CA 的公钥验证 example.com 的签名 → 合法 → 信任 example.com这就是信任链的传递。从根到中间到叶子一层验一层。只要你的操作系统信任根整条链就是可信的。操作系统里根证书列表有多大来直接在命令行看看macOSsecurity trust-settings-export或者看看/System/Library/Keychains/里的文件。每个操作系统出厂时预装了大约 100-200 个根证书。包括 GlobalSign、DigiCert、Let’s EncryptISRG、Microsoft、Google、中国的 CA沃通、CFCA 等。你手动安装的抓包 CA会被添加到这个列表里。从此以后它跟预装的根证书有同等的信任级别——它签发的任何证书都会被信任。CRL 和 OCSP证书被吊销了怎么办一个问题某天你发现自己的私钥泄露出去了你的网站证书不能再用了。你怎么办你联系你的 CA把我的证书吊销了。CA 照做。但问题是——CA 怎么通知全世界这个证书不能再用了方法一CRLCertificate Revocation ListCA 定期发布一个列表里面是所有被吊销的证书的序列号Certificate Revocation List (CRL) 签发者Lets Encrypt R3 本次更新2026-07-28 10:00:00 UTC 下次更新2026-07-29 10:00:00 UTC 吊销的证书 序列号 0x12345678吊销日期 2026-07-20 序列号 0x23456789吊销日期 2026-07-22 ……浏览器访问网站时去下载这个 CRL检查网站证书的序列号是否在列表里。但 CRL 有个问题列表越来越大。一个 CA 可能已经签发了上亿个证书被吊销的也有几百万。每次都要下载整个列表可能几十 MB——太慢了。所以有了方法二。方法二OCSPOnline Certificate Status Protocol浏览器不下载整个列表而是实时查询 CA“证书序列号 0x12345678现在还活着吗”客户端 → CA 的 OCSP 服务器 证书序列号 0x12345678 签发者 Lets Encrypt R3 OCSP 服务器 → 客户端 状态good或者 revoked、unknown但 OCSP 也有两个问题隐私问题CA 的 OCSP 服务器可以知道你在访问哪个网站虽然它不知道你具体做了什么但它知道你问了这个证书的状态——等于知道了你在访问哪个网站超时问题浏览器请求 OCSP 时如果 CA 的服务器没有响应浏览器一般会软失败——允许继续访问不阻塞。这给了中间人可乘之机中间人只要阻止 OCSP 请求出去浏览器就不会收到证书已被吊销的信息方法三OCSP Stapling更优的解决方案让服务器自己在 TLS 握手时附带OCSP 响应而不是让浏览器自己去查。TLS 握手阶段 客户端ClientHello 服务器Certificate OCSP StaplingCA 提前签好给我的证明这个证书在 X 时间前还是有效的浏览器不需要自己查 OCSP 了。服务器替它查好了把结果钉在握手消息里发过来。好处更快不需要额外的 HTTP 请求、更隐私CA 不知道谁在查。Certificate Transparency证书透明度Google 在 2013 年推出了 Certificate Transparency。它的动机很简单即使 CA 签发假证书也需要让所有人都能看到。怎么做到的所有 CA 签发的证书都要被提交到公开的日志服务器Log Server日志是只追加的append-only用 Merkle Tree 保证日志不被篡改浏览器在 TLS 握手时可能会检查证书是否出现在日志中通过证书中的 SCT——Signed Certificate Timestamp没在日志中出现过的证书 → 浏览器认为可疑这对中间人有什么影响如果你的抓包 CA 签发了假证书——这个假证书不会出现在公开的日志中。因为抓包 CA 不是你安装的那个公开 CA它不会把自己的日志提交到 Google 的 CT 日志服务器。所以浏览器可以看到这个证书的 SCT 是空的它可以据此发出警告。但注意这个检查并不是强制的。Chrome 在逐步推进它但到今天为止如果你的 CA 是用户手动安装的而非系统预装的Chrome 对这个 CA 签发的证书的 CT 检查相对宽松。而且——装你抓包 CA 的不是普通的网站运营者是你自己。你主动安装了它代表你知情同意了可能的风险。所以 CT 防的是CA 被黑后签发假证书的场景不是用户主动装了一个恶意 CA的场景。所以回到中间人为什么装证书是关键现在你应该完全理解了。在正常的 HTTPS 连接中客户端信任操作系统预装的 200 根证书 ↓ 信任链 真正的 CA 签发了 example.com 的证书 ↓ 客户端验证通过 连接安全 ✓在中间人攻击中客户端信任操作系统预装的 200 根证书 **你安装的抓包 CA** ↓ 信任链 抓包 CA 签发了假 example.com 证书 ↓ 客户端验证通过因为 CA 是你装的那个 连接被劫持 ✗但客户端不知道整个 MiTM 所有花里胡哨的技术全建立在同一个前提上你安装了对抓包工具的根证书。不装这个证书所有中间人操作都是白费——浏览器会立刻报证书错误。装了你的所有 HTTPS 在你选的抓包工具面前就是裸奔的。下期预告MITM 的五脏六腑。我们把中间人攻击拆成五步——堵路、分身、造假、偷看、传话。每一步的具体操作细节以及每一步如果出了问题会怎样。DumpAny 怎么做DumpAny 在安装时会提示用户导入自己的 CA 根证书。这个证书跟系统里其他受信任的 CA 拥有同等权限——但仅限于用户的明确授权。一个设计上容易被忽略的细节是CA 私钥的保护。如果私钥泄露了任何人都能冒充你的 DumpAny CA。所以 DumpAny 在生成 CA 时使用了唯一的、带密码保护的私钥存储每次新版本发布也不会替换用户的已有 CA避免用户需要重新安装证书。签发签发签发伪造签发根证书预装在操作系统中中间CA证书Lets Encrypt R3网站证书example.com浏览器验证通过 ✓根证书恶意CA抓包工具CA假证书假 example.com浏览器也通过因为CA是你装的