当浏览器连接到 HTTPS 站点时,它不会盲目信任证书。它会验证一条信任链——从你的站点证书到预信任的根证书颁发机构(CA)的一系列相互关联的证书。
三个层级
┌─────────────────────────────────┐
│ ROOT CA │ 预装在浏览器/操作系统中
│ (ISRG Root X1 for LE) │ 自签名,长有效期(20+ 年)
└───────────────┬─────────────────┘
│ signs
▼
┌─────────────────────────────────┐
│ INTERMEDIATE CA │ 由根 CA 签名
│ (Let's Encrypt R3/R10) │ 中等有效期(5-10 年)
└───────────────┬─────────────────┘
│ signs
▼
┌─────────────────────────────────┐
│ YOUR CERTIFICATE │ 由中间 CA 签名
│ (example.com) │ 短有效期(LE 为 90 天)
└─────────────────────────────────┘
根 CA —— 受浏览器和操作系统信任。存储在设备的证书存储中。自签名(没有人为根 CA 签名——它本身就是信任锚点)。根密钥保存在离线硬件安全模块中。
中间 CA —— 由根 CA 签名。实际负责签发终端证书。如果中间 CA 被入侵,只需吊销它——根 CA 保持安全。
终端证书 —— 你的证书。由中间 CA 签名。这是你的服务器发送给浏览器的证书。
验证流程
当浏览器收到证书时:
- 读取你的证书 —— 提取签发者名称
- 查找中间 CA —— 从服务器响应或浏览器缓存中获取
- 验证中间 CA 签名 —— 检查它是否由受信任的根 CA 签名
- 验证你的证书签名 —— 检查它是否由中间 CA 签名
- 检查有效期 —— 两张证书都没有过期
- 检查域名匹配 —— 证书的 SAN/CN 与 URL 匹配
- 检查吊销状态 —— 证书未被吊销(OCSP/CRL)
如果任何步骤失败 → 浏览器显示安全警告。
为什么中间 CA 很重要
最常见的 SSL 错误是缺少中间证书。如果你的服务器只发送了你的证书而没有中间证书,浏览器就无法构建信任链。
Nginx 需要 fullchain.pem(你的证书 + 中间证书合并):
ssl_certificate /etc/ssl/fullchain.pem; # cert + intermediate
Apache 使用单独的文件:
SSLCertificateFile /etc/ssl/cert.pem # your cert
SSLCertificateChainFile /etc/ssl/chain.pem # intermediate
GetHTTPS 同时提供 fullchain.pem 和单独的 cert.pem + chain.pem 文件,确保你拥有适配任何服务器的正确格式。
Let’s Encrypt 的证书链
Let’s Encrypt 当前的信任链:
ISRG Root X1 (root, in all trust stores)
└── Let's Encrypt R10 (intermediate, signs your cert)
└── yourdomain.com (your certificate)
还有一条通过 IdenTrust 的 DST Root CA X3 的交叉签名路径以兼容旧设备,但对大多数场景已不再需要。
常见问题
如何修复”证书不受信任”错误?
几乎总是:缺少中间证书。使用 fullchain.pem(Nginx)或添加 SSLCertificateChainFile chain.pem(Apache)。使用以下命令测试:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com
查找 “verify return:1”(正常)或 “verify return:0”(链有问题)。
能在浏览器中查看证书链吗?
可以。点击锁头图标 → “证书”(或”连接是安全的” → “证书有效”)。你将看到链条:你的证书 → 中间 CA → 根 CA。
如果根 CA 被入侵会怎样?
该根 CA 会通过浏览器/操作系统更新从信任存储中移除。在该根 CA 下签发的所有证书都变为不受信任。这极为罕见——根密钥存储在带有物理访问控制的离线硬件安全模块中。
为什么 Let’s Encrypt 使用中间证书而不是直接用根 CA 签名?
安全隔离。如果中间密钥被入侵,只需吊销它——根 CA 保持安全。根密钥保存在离线状态,仅用于签名中间证书。这是所有主要证书颁发机构的标准做法。
需要在服务器上安装根证书吗?
不需要。根证书预装在浏览器和操作系统中。你的服务器只需发送你的证书 + 中间证书。浏览器已经拥有根证书,用它来验证信任链。
调试证书链问题
生产环境中最常见的 SSL 错误是证书链不完整。以下是系统性的诊断方法:
步骤 1:检查服务器发送的证书链
echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null
查看输出:
Certificate chain
0 s:CN = example.com
i:C = US, O = Let's Encrypt, CN = R10
1 s:C = US, O = Let's Encrypt, CN = R10
i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
---
Verify return code: 0 (ok)
- Depth 0 = 你的证书
- Depth 1 = 中间证书
- “Verify return code: 0 (ok)” = 链条完整
如果只看到 depth 0(没有 depth 1),说明缺少中间证书。
步骤 2:修复证书链
Nginx: 使用 fullchain.pem(证书 + 中间证书合并):
ssl_certificate /etc/ssl/fullchain.pem; # NOT cert.pem
Apache: 显式添加中间证书:
SSLCertificateChainFile /etc/ssl/chain.pem
如果丢失了 chain.pem: 从 letsencrypt.org/certificates 下载 Let’s Encrypt 的中间证书,或使用 GetHTTPS 重新签发证书。
步骤 3:验证修复结果
echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | grep "Verify return code"
# Must say: Verify return code: 0 (ok)