Skip to content

数字证书与 CA 信任链

基于 HTTP 现代标准 · 核于 2026-06

速查

  • 加密只解决「不被偷看」,但不能确认对面是谁——若中间人把自己的公钥换上来,你以为在加密给银行,其实在加密给攻击者。证书就是用来**绑定「公钥 ↔ 身份」**的。
  • 数字证书 = 公钥 + 身份信息 + CA 数字签名,标准格式是 X.509:核心字段有主体(Subject CN / SAN)、颁发者(Issuer)、有效期(Not Before / Not After)、公钥、序列号、签名与签名算法。
  • CA(证书颁发机构)是被公认可信的第三方:它核验申请者确实控制该域名/身份后,用自己的私钥给证书签名作担保。
  • 信任链:根 CA → 中间 CA → 站点(叶子)证书,逐级签名。验证时反向逐级验签,一直追到本地信任的根。
  • 根证书内置于操作系统 / 浏览器的信任库(Root Store,如 Mozilla、Apple、Microsoft 的根计划),是整条链的信任锚点;根 CA 通常离线,日常签发交给中间 CA。
  • 浏览器验证证书四件事:① 签名链可一路验到受信根 ② 在有效期内 ③ 域名匹配(用 SAN,不再看 CN) ④ 未被吊销;任一不过即告警/中断。
  • 域名匹配看 SAN:现代浏览器只认 subjectAltName 扩展里的域名,CN 已被忽略;支持 *.example.com 这类通配符。
  • 吊销应对「私钥泄露 / 误签发」:三种机制——CRL(吊销清单,大而慢)、OCSP(在线逐张查,泄露隐私且增延迟)、OCSP Stapling(服务器代查并把带时间戳的应答「钉」在握手里,最优)。
  • 证书透明度(CT):新证书被记入公开的只追加 Merkle 日志,签发时生成 SCT 作为收录凭证;Chrome / Safari / Firefox 已强制要求 CT,用以事后发现误签发
  • 一句话:证书把「难验证的身份」转化为「可机器验证的密码学签名链」,信任最终都收敛到本地那几百张内置根证书。

加密之外:公钥到底是谁的?

上一页讲清了非对称加密——浏览器拿服务器的公钥加密、只有持私钥者能解。但这里藏着一个致命前提:你怎么确定手里这把公钥真的是 bank.com 的,而不是中间人塞过来的?

设想一个主动攻击者坐在链路中间:你向 bank.com 要公钥,他拦截下来、把自己的公钥回给你。你高高兴兴用它加密了密码——结果直接加密给了攻击者。加密本身完好无损,崩的是公钥的归属

核心问题

非对称加密保证「只有私钥持有者能解密」,却不保证这把公钥属于你以为的那个人。把公钥和真实身份绑定起来、并让这绑定可被第三方验证,正是数字证书要解决的唯一问题。

数字证书:可验证的「公钥身份证」

数字证书把三样东西打包并由权威方背书:公钥 + 身份信息 + CA 的数字签名。业界标准格式是 X.509(v3),一张站点证书的核心字段如下:

字段含义要点
Subject证书主体(被认证方)内含通用名 CN(如 bank.com)等;但域名匹配现在看 SAN,不看 CN
Subject Alternative Name(SAN)该证书覆盖的域名列表现代浏览器只认 SAN;可含多个域名与 *.example.com 通配符
Issuer颁发者(签名方 CA 的名称)指向上一级证书,是串起信任链的线索
Validity(Not Before / Not After)有效期起止过期或尚未生效都判失败;现代证书有效期已大幅缩短(趋向 ≤ 1 年甚至更短)
Public Key本主体的公钥握手中用它做密钥交换/验签(RSA、ECDSA 等)
Serial Number颁发者内唯一的序列号吊销时用它定位某张具体证书
Signature + 算法CA 用自己私钥对证书内容的签名任何人可用 CA 公钥验签,确认「内容没被篡改、确由该 CA 签发」
ExtensionsX.509v3 扩展含 SAN、密钥用途、吊销信息地址、嵌入的 CT 凭证(SCT)等

签名 ≠ 加密

CA 的「签名」是对证书内容做哈希后用 CA 私钥加密得到的;验证方用 CA 公钥还原哈希并比对。它不保护机密性(证书本就是公开的),只保护完整性 + 来源真实性——证明「这份公钥-身份绑定,是这个 CA 认可的,且没被改过」。

把这些字段落到实处,用 openssl 读一张真实证书大致是这样(节选):

text
Certificate:
  Subject: CN = bank.com                         # 主体通用名
  Issuer:  C = US, O = Let's Encrypt, CN = R3     # 颁发者 = 某中间 CA
  Validity:
    Not Before: Jun  1 00:00:00 2026 GMT          # 生效时间
    Not After : Aug 30 23:59:59 2026 GMT          # 过期时间(已趋向短周期)
  Subject Public Key Info: ... (ECDSA / RSA)      # 本主体公钥
  X509v3 extensions:
    X509v3 Subject Alternative Name:
        DNS:bank.com, DNS:*.bank.com               # 域名匹配只看这里
    Signature Algorithm: ecdsa-with-SHA384         # CA 用何种算法签名

IssuerR3(一个中间 CA)而非根,正说明日常证书都由中间 CA 签发——这就引出了信任链。

CA 与信任链:信任如何逐级传递

单张证书只是「某 CA 说这把公钥属于 bank.com」。可你凭什么信这个 CA?答案是信任链——把信任一级级往上挂,直到一个你本来就信的锚点。

三级角色

  • 根 CA(Root):信任的最终源头。其根证书是自签名的(自己给自己签),靠的不是别人背书,而是被预装进信任库这一事实。根 CA 极其敏感,私钥通常离线保管,平时不直接签站点证书。
  • 中间 CA(Intermediate):根 CA 签发给它一张「可以再签发」的证书,日常签发工作由它承担。这样根私钥能离线,万一中间 CA 出事也可单独吊销、不动根。可以有多级中间 CA。
  • 站点 / 叶子证书(Leaf):由中间 CA 签发给具体域名,就是你网站部署的那张。
text
[根 CA 证书]  自签名 · 预装在 OS/浏览器信任库 ← 信任锚点
      │  用根私钥签发

[中间 CA 证书]  Issuer = 根 CA
      │  用中间私钥签发

[站点证书 bank.com]  Issuer = 中间 CA · 含公钥 + SAN

服务器要发「整条链」

站点部署时应同时配置叶子证书 + 中间证书(合称证书链 / fullchain),否则部分客户端的信任库里若没有该中间证书,就会因「链断了、追不到根」而验证失败。根证书无需也不应由服务器下发——它本就在客户端本地。(证书在握手中具体如何传输,见下一页。)

根证书:内置的信任锚点

整条链能不能成立,全看链顶那张根证书是否在本地信任库里。各大根计划——Mozilla(Firefox 及众多 Linux)、Apple、Microsoft、Google——各自维护一份受信根 CA 列表,随操作系统/浏览器分发。一个 CA 要想其证书被普遍信任,必须先通过审计、被纳入这些根计划。

这也解释了几类常见现象:企业内网装「自签证书」会报错,是因为它的根不在公共信任库;公司给员工机器手动导入内部根 CA 后,内网 HTTPS 才不报警——本质就是往信任库里加了一个新锚点(这也是企业中间盒能解密流量的原理,详见「中间人攻击」一页)。

浏览器如何验证一张证书

握手时拿到服务器证书(链)后,客户端按下面四步校验,任一步失败就终止连接并告警

  1. 构建并验证签名链:从叶子证书的 Issuer 找到中间证书,验证「叶子的签名确由该中间 CA 私钥签出」;再用同样方式上溯,直到链顶证书是本地信任库中的受信根。链中任一签名对不上、或追不到受信根 → 失败(典型报错:unknown issuer / self-signed certificate)。
  2. 检查有效期:当前时间须落在每张证书的 Not BeforeNot After 之间。过期或时钟异常都会失败(certificate expired)——所以本机时间错乱常导致全站 HTTPS 报错。
  3. 校验域名匹配:访问的主机名必须命中证书 SAN 中的某个条目(精确或通配符)。对不上 → common name/SAN mismatch(你访问 a.com 却拿到 b.com 的证书时就是它)。
  4. 检查是否被吊销:通过 CRL / OCSP / OCSP Stapling(见下节)确认证书未在有效期内被提前作废。

链的强度取决于最弱一环

信任链是「与」的关系:根受信、且每级签名都对、且叶子没过期没被吊销、且域名匹配,全部成立才算可信。任何一环被攻破(如某中间 CA 被黑、误签发),都可能签出一张「看似合法」的证书——这正是下面 CT 机制要兜底的场景。

把验证步骤对照成浏览器报错

前端排查 HTTPS 故障时,浏览器的错误码几乎都能对回上面某一步。常见对照(Chrome 的 NET::ERR_CERT_*):

报错 / 现象对应失败的验证步常见原因
ERR_CERT_AUTHORITY_INVALID / unknown issuer① 签名链追不到受信根自签证书、内部 CA 未导入、服务器漏配中间证书
ERR_CERT_DATE_INVALID / expired② 有效期证书过期、未续期,或本机系统时间不准
ERR_CERT_COMMON_NAME_INVALID / mismatch③ 域名匹配访问的主机名不在 SAN 内、用了不覆盖的子域、证书只配了裸域没配 www
ERR_CERT_REVOKED④ 吊销证书被 CA 提前作废(私钥泄露/误签发后被吊销)

漏配中间证书最隐蔽

本机/某些浏览器能打开、换台机器或用 curl 却报 unknown issuer,十有八九是只部署了叶子证书、漏了中间证书:碰巧本地信任库缓存过该中间 CA 的环境能补全链、干净环境补不上。部署时务必用 fullchain(叶子 + 中间)。

证书吊销:让「还没到期」的证书提前失效

证书有有效期,但私钥泄露、信息有误、CA 误签发等情况需要在到期前就让它作废。难点在于:证书已经发到全世界,怎么高效地通知「这张别信了」?三种机制各有取舍:

  • CRL(Certificate Revocation List,证书吊销列表):CA 定期发布一份「已吊销证书序列号」的清单,客户端下载后比对。问题:清单越积越大、有缓存延迟,实时性和性能都差。
  • OCSP(Online Certificate Status Protocol,在线证书状态协议):客户端就单张证书向 CA 的 OCSP 响应器实时查询「有效/已吊销」。问题:① 每次访问都多一次网络往返,增加延迟;② CA 因此能看到「谁在访问哪个站点」,有隐私泄露;③ 响应器宕机时如何处理(硬失败会拖垮可用性,软失败又给了攻击者可乘之机)也是难题。
  • OCSP Stapling(OCSP 装订):改由服务器自己定期向 CA 拉取带时间戳和 CA 签名的 OCSP 应答,并在 TLS 握手时把它「钉」给客户端。客户端无需自己联系 CA——消除了额外往返与隐私泄露,是当前推荐做法(通过 TLS status_request 扩展实现)。

吊销之外的兜底:证书透明度(CT)

吊销解决「已知坏证书」,但误签发往往先被滥用、才被发现证书透明度(Certificate Transparency) 要求每张新证书被记入公开的、只追加的 Merkle 树日志;签发时日志返回一个 SCT(Signed Certificate Timestamp,签名证书时间戳) 作为「已收录」凭证,可经 X.509 扩展嵌入证书、TLS 扩展或 OCSP Stapling 下发。域名持有者借此能主动监控有没有人偷偷为自己的域名签了证书。Chrome、Safari、Firefox 现已强制要求公共信任证书带合规 CT 凭证,否则不予信任。

小结

数字证书把「公钥到底属于谁」这个难题,转化成一条可被机器逐级验证的密码学信任链:站点证书(公钥 + 身份)由中间 CA 签名、中间 CA 由根 CA 签名,而根证书内置于 OS/浏览器信任库充当信任锚点。浏览器验证时逐级验签、查有效期、用 SAN 匹配域名、再查吊销(CRL / OCSP / OCSP Stapling),辅以证书透明度兜底误签发。证书背后的公钥/私钥与签名机制,建立在上一页 对称与非对称加密 之上;而这条链上的证书在连接建立时究竟如何传输、双方又如何据此协商出会话密钥,是下一页 TLS 握手流程 的主题。