🏠 总目录📚 本教程 18 · PKI 与证书
📑 本页目录(点开跳转)

18 · PKI 与证书

28 分钟 | ⭐ 浏览器那把小锁背后发生了什么


🎯 一句话

公钥可以公开 —— 但你怎么知道拿到的公钥真的属于 google.com,而不是攻击者的? PKI 的答案是:找一个大家都信的第三方,让它给"公钥↔身份"的绑定签个名。

根 CA预装在你的系统/浏览器里中间 CA由根 CA 签名网站证书由中间 CA 签名签名签名浏览器沿这条链一路往上验,直到遇到它「本来就信」的那个⚠️ 整条链的信任,最终都压在「根 CA 没被攻破」这一个假设上根 CA 一旦失守,它签过的一切都可以被伪造
浏览器沿着签名链一路往上验,直到遇到它本来就信任的根 CA。⚠️ 整个体系的安全性,最终压在「根 CA 没被攻破」这一个假设上 —— DigiNotar 事件证明了这个假设会破。

🔗 一、信任链

   根证书(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 握手:把前面全部串起来

Client Server ClientHello + 支持的算法 + 【ECDHE 公钥】⭐(第 15、16 章) ServerHello + 【ECDHE 公钥】 + 【证书】(第 18 章) + 【证书验证签名】⭐(第 17 章) + Finished (MAC) Finished 应用数据(AES-GCM 加密) (第 11 章)
看回合数:一来一回就完事了(1-RTT)。客户端第一句就把 ECDHE 公钥甩了出去,所以服务端回信时双方已经能各自算出密钥,紧接着就能开始传加密数据。

每一步对应你学过的哪一章

步骤 用到的知识
双方交换 ECDHE 公钥 第 1516 章 → 得到共享密钥,且有前向保密
服务器发证书 本章 → 证明公钥属于这个域名
服务器对握手内容签名 第 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 资料库 · 零信任架构 零信任要求「每一跳都验证身份」;⚠️ 而本章第 ⑤ 步(域名匹配)正是这条要求在真实客户端里最常被跳过的一步

✅ 检查点

  1. PKI 解决的核心问题是什么?
  2. 浏览器验证证书的七个步骤,哪一步最常被自己写代码的人漏掉?后果是什么?
  3. 为什么要有中间 CA?
  4. Basic Constraints 漏洞是怎么回事?
  5. 四种吊销机制各有什么问题?业界的实际答案是什么?
  6. PKI 的根本弱点是什么?举一个真实事故。
  7. CT 为什么被认为是最成功的缓解手段?它体现了什么设计思路?
  8. TLS 握手里"证书验证签名"这一步为什么必要?
  9. TLS 1.3 的四个关键改进?
👀 答案
  1. 怎么确认拿到的公钥真的属于这个身份。答案是找一个大家都信的第三方(CA),给"公钥↔身份"的绑定签名。
  2. 第⑤步域名匹配(SAN 检查)最常被漏。后果:"签名有效"和"这张证书是给这个域名的"是两回事,攻击者用任意一张合法域名的证书就能做中间人。大量移动 App 和 API 客户端栽在这里。
  3. 因为根 CA 的私钥离线保存在 HSM 里,只用来签中间 CA。中间 CA 泄露可以吊销换新;根 CA 泄露是灾难——它预装在几十亿台设备里,换不掉。
  4. 早期实现不检查 CA:TRUE 标志,导致任何持有普通证书的人都能用它签发别的证书,拿一张自己域名的证书就能冒充任何网站。影响过 IE、Konqueror、2011 年的 iOS。
  5. CRL 列表越来越大且更新不及时;OCSP 泄露隐私(CA 知道你访问了谁)且 CA 挂了就没法查;OCSP Stapling 服务器可以不 staple;短有效期是实际主流答案。业界结论:吊销机制都不好用,干脆缩短有效期(90 天 → 正在推进 47 天)。
  6. 任何一个受信任的 CA 都能给任何域名签发证书,整个体系的安全性等于最弱的那一家。DigiNotar(2011)被入侵后为 *.google.com 签发假证书监控伊朗用户,CA 直接破产。
  7. 因为它不阻止误签发,但让误签发一定会被发现。思路:把"预防"换成"必然被审计"——在无法预防时这是更现实的设计。
  8. 因为证书是公开的,谁都能拿到 google.com 的证书。必须让服务器用私钥签一下当前握手,才能证明"我不只是拿到了证书,我还持有私钥"。
  9. 删掉 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

打卡记录保存在你的浏览器里,首页能看到总进度