📑 本页目录(点开跳转)
18 · PKI 与证书
⏱ 28 分钟 | ⭐ 浏览器那把小锁背后发生了什么
🎯 一句话
公钥可以公开 —— 但你怎么知道拿到的公钥真的属于 google.com,而不是攻击者的? PKI 的答案是:找一个大家都信的第三方,让它给"公钥↔身份"的绑定签个名。
🔗 一、信任链
根证书(Root CA) ← 【预装在操作系统/浏览器里】⭐
│ 签名
▼
中间 CA 证书
│ 签名
▼
google.com 的证书 ← 包含 google.com 的公钥
浏览器验证的时候做什么:
① 用中间 CA 的公钥,验证叶子证书的签名 ✅
② 用根 CA 的公钥,验证中间 CA 证书的签名 ✅
③ 检查根 CA 在【本地信任库】里 ✅
④ 检查有效期没过 ✅
⑤ 检查【域名匹配】(SAN 字段包含 google.com)⭐
⑥ 检查没被吊销
⑦ 检查 CT 日志(第 12 章)
⚠️ 第 ⑤ 步经常被自己写代码的人漏掉: "证书签名有效"和"这张证书是给这个域名的"是两回事。 💥 大量移动 App 和 API 客户端栽在这里 —— 攻击者用一张任意合法域名的证书就能做中间人。
💡 为什么要有中间 CA
⭐ 根 CA 的私钥【离线保存】(真的在保险柜里的 HSM 中)
只用来签中间 CA,一年可能就用几次
→ 中间 CA 泄露了可以吊销并换一个
→ 根 CA 泄露 = 灾难(它预装在几十亿台设备里,换不掉)⭐
📜 二、证书里有什么
X.509 证书的关键字段:
├─ Subject 谁的证书(CN / SAN 域名列表)⭐
├─ Issuer 谁签的
├─ Public Key ⭐ 核心内容
├─ Validity 有效期
├─ Serial Number 序列号(吊销时用)
├─ Extensions
│ ├─ SAN ⭐ 实际用的域名列表(CN 已废弃)
│ ├─ Basic Constraints ⭐ 是不是 CA 证书
│ ├─ Key Usage 这个密钥能干什么
│ └─ SCT 证书透明性凭证
└─ Signature CA 的签名
💥 Basic Constraints 的著名漏洞: 早期一些实现不检查
CA:TRUE这个标志 → 任何持有普通证书的人都能用它去签发别的证书 → 拿到一张自己域名的证书就能冒充任何网站。 影响过 IE、Konqueror、以及 2011 年的 iOS。
🚫 三、吊销:一个至今没解决好的问题
证书签发后想提前作废(私钥泄露、域名易主),怎么通知全世界?
| 机制 | 做法 | 问题 |
|---|---|---|
| CRL | CA 发布吊销列表,客户端下载 | 列表越来越大(几 MB),更新不及时 |
| OCSP | 客户端实时查询"这张证书还有效吗" | ⚠️ 隐私泄露(CA 知道你访问了谁);CA 挂了怎么办 |
| OCSP Stapling ⭐ | 服务器自己去查,把带签名的结果附在握手里 | 服务器可以"不 staple",需要 Must-Staple 标志 |
| 短有效期 ⭐⭐ | 证书只有 90 天甚至 7 天 | 实际上是当前的主流答案 |
| CRLite / 推送式 | 浏览器厂商聚合后推送压缩集合 | 只有大厂能做 |
🔑 业界的实际结论:吊销机制都不太好用,所以干脆缩短有效期。 Let's Encrypt 推动了 90 天证书 + 自动续期, CA/浏览器论坛已经在推进 47 天甚至更短。
💡 背后的思路很实用:与其想办法快速撤销,不如让证书本身很快过期。
💥 四、PKI 的根本弱点
⭐ 任何一个受信任的 CA,都能给【任何域名】签发证书
→ 全球有几十家根 CA、几百家中间 CA
→ 整个体系的安全性 = 【最弱的那一家】⭐
真实的 CA 事故:
| 事故 | 发生了什么 |
|---|---|
| DigiNotar(2011) | 荷兰 CA 被入侵,为 *.google.com 签发假证书,用于监控伊朗用户。CA 直接破产 ⭐ |
| Comodo(2011) | 转售商被攻破,签发了 9 张知名域名的假证书 |
| Symantec(2015–2017) | 多次未经授权签发证书,Google 最终不再信任其根证书 |
| TrustCor(2022) | 因与监控软件公司的关联被移出信任库 |
缓解手段:
| 手段 | 做法 |
|---|---|
| 证书透明性 CT ⭐ | 所有证书必须进公开日志 → 偷偷签发会被发现(第 12 章) |
| CAA 记录 | 域名所有者在 DNS 里声明"只有 X 能给我签证书" |
| 证书固定 Pinning | App 硬编码期望的证书/公钥 ⚠️ 但固定的密钥换了会导致全线故障 |
| DANE | 把证书信息放进 DNSSEC |
🔑 CT 是这里最成功的一个: 它不阻止误签发,但让误签发一定会被发现 —— 把"预防"换成"必然被审计",这在无法预防时是更现实的设计。
🔐 五、TLS 1.3 握手:把前面全部串起来
每一步对应你学过的哪一章:
| 步骤 | 用到的知识 |
|---|---|
| 双方交换 ECDHE 公钥 | 第 15、16 章 → 得到共享密钥,且有前向保密 ⭐ |
| 服务器发证书 | 本章 → 证明公钥属于这个域名 |
| 服务器对握手内容签名 | 第 17 章 → 证明它真的持有证书里那个公钥的私钥 ⭐ |
| 派生会话密钥 | HKDF(第 13 章提到的 KDF) |
| 加密应用数据 | 第 11 章 AEAD |
🔑 注意"证书验证签名"这一步的必要性: 光有证书不够 —— 证书是公开的,谁都能拿到 google.com 的证书。 必须让服务器用私钥签一下当前握手,才能证明"我不只是拿到了证书,我还有私钥"。
💡 TLS 1.3 相比 1.2 的关键改进: ① 删掉了 RSA 密钥传输 → 强制前向保密(第 15 章) ② 删掉了 CBC 模式和所有非 AEAD 密码套件 → 消灭 padding oracle ③ 握手从 2-RTT 降到 1-RTT ④ 握手内容也被加密(证书不再明文可见)
🔗 和站内其他章的关系
| 相关的地方 | 和这一章的关系 |
|---|---|
| 第 17 章 数字签名 | 证书就是 CA 的一个签名 |
| 第 12 章 Merkle 树 | 证书透明性日志 ⭐ |
| 第 15 章 前向保密 | TLS 1.3 强制 ECDHE 的原因 |
| 第 11 章 AEAD | TLS 1.3 只保留 AEAD |
| 第 7 章 padding oracle | TLS 1.3 删掉 CBC 的原因 |
| 智能体教程 · MCP 接入外部世界 | 「接一个 MCP Server,你凭什么信它」和 PKI 是同一个信任根问题:信任必须从带外来,不能由被验证的那一方自己提供 ⭐ |
| Claude 资料库 · 零信任架构 | 零信任要求「每一跳都验证身份」;⚠️ 而本章第 ⑤ 步(域名匹配)正是这条要求在真实客户端里最常被跳过的一步 |
✅ 检查点
- PKI 解决的核心问题是什么?
- 浏览器验证证书的七个步骤,哪一步最常被自己写代码的人漏掉?后果是什么?
- 为什么要有中间 CA?
- Basic Constraints 漏洞是怎么回事?
- 四种吊销机制各有什么问题?业界的实际答案是什么?
- PKI 的根本弱点是什么?举一个真实事故。
- CT 为什么被认为是最成功的缓解手段?它体现了什么设计思路?
- TLS 握手里"证书验证签名"这一步为什么必要?
- TLS 1.3 的四个关键改进?
👀 答案
- 怎么确认拿到的公钥真的属于这个身份。答案是找一个大家都信的第三方(CA),给"公钥↔身份"的绑定签名。
- 第⑤步域名匹配(SAN 检查)最常被漏。后果:"签名有效"和"这张证书是给这个域名的"是两回事,攻击者用任意一张合法域名的证书就能做中间人。大量移动 App 和 API 客户端栽在这里。
- 因为根 CA 的私钥离线保存在 HSM 里,只用来签中间 CA。中间 CA 泄露可以吊销换新;根 CA 泄露是灾难——它预装在几十亿台设备里,换不掉。
- 早期实现不检查
CA:TRUE标志,导致任何持有普通证书的人都能用它签发别的证书,拿一张自己域名的证书就能冒充任何网站。影响过 IE、Konqueror、2011 年的 iOS。 - CRL 列表越来越大且更新不及时;OCSP 泄露隐私(CA 知道你访问了谁)且 CA 挂了就没法查;OCSP Stapling 服务器可以不 staple;短有效期是实际主流答案。业界结论:吊销机制都不好用,干脆缩短有效期(90 天 → 正在推进 47 天)。
- 任何一个受信任的 CA 都能给任何域名签发证书,整个体系的安全性等于最弱的那一家。DigiNotar(2011)被入侵后为 *.google.com 签发假证书监控伊朗用户,CA 直接破产。
- 因为它不阻止误签发,但让误签发一定会被发现。思路:把"预防"换成"必然被审计"——在无法预防时这是更现实的设计。
- 因为证书是公开的,谁都能拿到 google.com 的证书。必须让服务器用私钥签一下当前握手,才能证明"我不只是拿到了证书,我还持有私钥"。
- ①删掉 RSA 密钥传输强制前向保密 ②删掉 CBC 和所有非 AEAD 套件,消灭 padding oracle ③握手 2-RTT 降到 1-RTT ④握手内容也加密(证书不再明文可见)。
🛑 可以停在这里
⚡ 走神救援
PKI 解决"怎么确认这个公钥真的属于 google.com"——找可信第三方给"公钥↔身份"签名。信任链:根CA(预装在系统里)签中间CA,中间CA签叶子证书。验证七步:验签名链 → 根在信任库 → 有效期 → ⭐域名匹配(SAN) → 未吊销 → CT;⚠️第四步最常被漏——"签名有效"和"这张证书是给这个域名的"是两回事,漏了就能被任意合法证书做中间人(大量移动App栽在这)。中间CA 的意义:根CA私钥离线在HSM里,中间CA泄露能换,根CA泄露是灾难(预装在几十亿设备里)。💥Basic Constraints 漏洞:不检查
CA:TRUE就能用普通证书签发别的证书(影响过 IE、2011 iOS)。吊销至今没解决好:CRL 太大、OCSP 泄露隐私且 CA 挂了没法查、Stapling 可以不 staple → ⭐业界实际答案是缩短有效期(Let's Encrypt 90天,正推进47天)——与其快速撤销不如让它很快过期。⭐根本弱点:任何一个受信任 CA 都能给任何域名签证书,安全性 = 最弱的那一家;💥DigiNotar(2011)被入侵为 *.google.com 签假证书监控伊朗用户,CA 直接破产;Symantec 因多次误签发被 Google 取消信任。缓解:⭐CT(最成功——不阻止误签发但让它一定被发现,把"预防"换成"必然被审计")、CAA 记录、Pinning(⚠️换密钥会全线故障)。TLS 1.3 握手串起全书:交换 ECDHE 公钥(前向保密)→ 发证书 → ⭐对握手签名(证书是公开的,必须签一下才能证明"我还持有私钥")→ HKDF 派生 → AEAD 加密。1.3 的四个改进:删掉 RSA 密钥传输强制前向保密、删掉 CBC 消灭 padding oracle、1-RTT、握手内容也加密。
下一节 👉 19-密钥管理.md