HTTPS 证书链不完整:浏览器不信任但解码「看起来正常」
症状:解码通过,浏览器失败
运维里最浪费时间的一类 TLS 故障是:
- 把叶证书粘进证书解码器,Not Before / Not After 都在窗口内
- SAN 里也有你的域名
- 手机 Safari / 部分企业代理 /
curl默认校验却报 unable to get local issuer certificate 或「证书不受信任」
这不是「证书假的」,而是信任路径断了:客户端拿不到(或对不上)签发这张叶证书的中间 CA。
证书链到底有几层
简化成三层就够日常排查:
| 层级 | 谁签发 | 谁信任它 |
|---|---|---|
| 叶(leaf / end-entity) | 中间 CA | 无人默认信任,靠链证明 |
| 中间(intermediate) | 根 CA 或上一级中间 | 浏览器/OS 通常不预置全部中间 |
| 根(root) | 自签 | 预置在信任库里 |
服务器必须下发:叶 + 足够的中间,让客户端能走到某个已信任的根。根证书一般不要塞进 nginx ssl_certificate 链(多余且部分客户端会挑剔)。
五分钟定位流程
1. 用 SNI 把链拉全
openssl s_client -connect www.example.com:443 \
-servername www.example.com -showcerts </dev/null
没有 -servername 时,多证书 IP 上可能拉到另一张证,排查会跑偏。
输出里数一数有几个 BEGIN CERTIFICATE:
- 只有 1 段:高度可疑——只发了叶
- 2 段及以上:把每一段存成
leaf.pem、int1.pem…
2. 核对衔尾:Issuer 必须等于下一级的 Subject
openssl x509 -in leaf.pem -noout -issuer -subject
openssl x509 -in int1.pem -noout -issuer -subject
期望:leaf 的 Issuer == int1 的 Subject;int1 的 Issuer 落在你信任的根(或再接一段中间)。对不上 = 链拼错或拿错文件。
站内解码器同样可读 PEM 字段——证书解码指南里有字段表;链验证本身请用本机 OpenSSL(浏览器解码器不做 PKIX 路径构建)。
3. 本机验证
# 系统信任库路径因发行版而异;也可用 CA 打包文件
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt \
-untrusted int1.pem leaf.pem
OK 才表示「在你这台机器的信任模型下路径闭合」。unable to get local issuer 几乎总是缺中间或 -untrusted 指错文件。
部署侧三类根因
A. 只上传了 leaf,没用 fullchain
Let's Encrypt / 多数 ACME 客户端会生成:
cert.pem:仅叶fullchain.pem:叶 + 中间
nginx / Caddy / 多数云负载均衡应指向 fullchain。只挂 cert.pem 时,桌面 Chrome 有时仍能「碰巧」缓存过中间证书而显示正常,移动端与严格客户端立刻翻车——这也是「我电脑上好好的」的经典来源。
B. 拼接顺序反了
正确顺序:叶在前,中间在后。反了之后有的栈直接握手失败,有的表现为间歇性不受信任。用上一节的 Issuer/Subject 衔尾检查,比肉眼扫 PEM 可靠。
C. 中间证书已过期或轮换
叶证书「还有 60 天」不代表链有效。2021 年前后 Let's Encrypt 中间轮换曾让大量「没动过业务证书」的站点同时报警。解码时每一级都看 Not After;只看叶是不够的。
和国密 / 双证书的关系
国密 TLCP 场景是签名证书 + 加密证书两套材料,链完整的要求同样存在,只是文件更多、顺序更敏感。部署清单见国密 HTTPS(Tongsuo / nginx)。国际算法栈的 RSA 密钥语境见 RSA 指南。
实现注记 / Implementer's note
本站证书工具只解析你粘贴的 PEM 字段,不会替你出站下载目标站证书,也不会做完整链验证——前者是 SSRF 与隐私边界,后者是 WebCrypto 能力边界。把「读字段」和「判信任」拆开,才能避免在线工具给出虚假的安全感。需要信任结论时:本机 openssl verify 或 SSL Labs;需要看清 SAN/日期/Issuer:用证书解码器。
快速检查清单
s_client -servername是否看到至少两段证书?- 叶 Issuer 是否等于第一段中间的 Subject?
- 服务器配置是否指向 fullchain 而非 leaf?
- 每一级 Not After 是否都未过期?
- 修复后是否 reload 了实际终结 TLS 的进程(容器 / 反代 / CDN 源站)?
相关阅读
本文由 ToolVault 工具匣 提供。更多开发者工具请访问 首页。
相关工具
相关文章
HTTP API 测试完全指南:从基础到高级调试技巧
掌握 HTTP API 测试的核心技巧,包括 GET/POST/PUT/DELETE 请求、请求头配置、请求体格式、认证方式和调试方法。使用在线 API 测试工具提升开发效率。
HTTP GET vs POST:什么时候用哪个?语义、安全与最佳实践
GET 和 POST 的语义差异、幂等性、缓存、URL 长度限制、安全考量、RESTful 约定、常见误用与 curl 示例。附决策表,帮你正确选择 HTTP 方法。
Unexpected token '<' is not valid JSON?接口返回 HTML 而不是 JSON 的 5 种原因
fetch 请求报 SyntaxError: Unexpected token '<' 是因为响应体是 HTML 不是 JSON。覆盖 5 种根因:SPA 路由兜底返回 index.html、登录 302 重定向、网关 502 错误页、baseURL 写错、忘了检查 res.ok,附 curl 排查命令。