3. 不完整证书链:服务器未发送中间证书

这个错误,我估计不少人都见过。

浏览器地址栏里一个大红叉,提示 NET::ERR_CERT_AUTHORITY_INVALID。很多人第一反应是“证书是不是过期了?”或者“CA 是不是被拉黑了?”

其实,大部分情况下,问题出在服务器没把中间证书发给浏览器。

3.1 为什么浏览器会报这个错?

咱们先理清一个概念:证书链。

你的服务器证书,不是根 CA 直接签的。中间 CA 签了你的证书,根 CA 又签了中间 CA。浏览器只信任根 CA,不直接信任你的服务器证书。

所以,当浏览器来验证时,它需要拿到完整的链条:

  • 你的服务器证书(叶子证书)
  • 中间 CA 证书
  • 根 CA 证书(浏览器内置)

如果服务器只发了自己的证书,没发中间证书,浏览器就找不到从叶子到根的信任路径。它就会认为这个证书是“自签名的”或者“不可信的”。

说白了,就是链条断了。

核心结论:服务器必须把中间证书和服务器证书一起发送给客户端。只发服务器证书,浏览器无法完成链式验证。

3.2 我在项目中遇到过的真实案例

我记得有一次,帮一个电商平台排查 HTTPS 问题。用户反馈说,用 Chrome 访问没问题,但用 Safari 就报错。

我一开始也纳闷,后来抓包一看,发现 Nginx 配置里只配了 ssl_certificate,没配 ssl_certificate_chain。Chrome 比较聪明,它会自己去尝试补全中间证书,但 Safari 比较严格,直接报错。

从那以后,我养成了一个习惯:配置完证书后,一定用 openssl 命令模拟一下握手,看看服务器到底发了哪些证书。

3.3 如何排查?

排查方法其实很简单,我一般用下面这几种方式:

3.3.1 使用 OpenSSL 命令行

这是最直接的方法。模拟一次 TLS 握手,看看服务器返回的证书链:

openssl s_client -connect yourdomain.com:443 -showcerts

你会看到类似这样的输出:

---
Certificate chain
 0 s:/CN=yourdomain.com
   i:/CN=Intermediate CA
-----BEGIN CERTIFICATE-----
...(服务器证书)...
-----END CERTIFICATE-----
 1 s:/CN=Intermediate CA
   i:/CN=Root CA
-----BEGIN CERTIFICATE-----
...(中间证书)...
-----END CERTIFICATE-----
---

如果只看到 0 s: 这一条,没有 1 s:,那就说明服务器没发中间证书。

小技巧:如果输出里只有一条证书,但你的证书明明是从正规 CA 买的,那 99% 是配置问题。去检查一下你的 Web 服务器配置文件吧。

3.3.2 使用在线 SSL 检测工具

如果你不想敲命令,也可以用一些在线工具。比如 SSL Labs 的 SSL Server Test。输入域名,它会帮你分析证书链是否完整。

我个人习惯先用命令行快速确认,再用在线工具出报告给客户看。

3.3.3 检查 Web 服务器配置

不同的 Web 服务器,配置方式不一样。我列个表格,方便你对照:

Web 服务器 配置指令 说明
Nginx ssl_certificate 将服务器证书和中间证书合并到一个文件中,服务器证书在上,中间证书在下
Apache SSLCertificateFile + SSLCertificateChainFile 旧版 Apache 需要单独指定 SSLCertificateChainFile;新版可以直接合并到 SSLCertificateFile
IIS 图形界面导入 在服务器证书导入向导中,选择“包含证书链中的所有证书”
HAProxy crt 同样需要将服务器证书和中间证书合并到一个 PEM 文件中

3.4 如何修复?

修复方法也很简单。你只需要把中间证书和服务器证书拼在一起。

假设你从 CA 那里拿到了三个文件:

  • yourdomain.crt(服务器证书)
  • intermediate.crt(中间证书)
  • root.crt(根证书,一般不需要)

在 Linux 下,用 cat 命令合并:

cat yourdomain.crt intermediate.crt > fullchain.crt

然后把 fullchain.crt 配置到你的 Web 服务器里。注意顺序:服务器证书必须在最上面,中间证书跟在后面。

注意:不要把根证书也加进去。浏览器内置了根证书,你再加进去反而可能引起问题。有些 CA 会要求你加,但绝大多数情况下不需要。

3.5 不完整证书链的典型场景

我总结了几种常见的情况,你可以对照看看:

  • 从 CA 下载证书时,只下载了服务器证书。很多 CA 的下载页面会提供多个文件,新手容易只点第一个。
  • 使用了自签名证书,但没配置中间证书。自签名证书本身就不需要中间证书,但如果你用了自建的 CA 体系,中间证书必须配。
  • 证书链文件顺序搞反了。把中间证书放在上面,服务器证书放在下面,浏览器也会报错。
  • 使用了 CDN 或反向代理。有些 CDN 默认不传递中间证书,需要手动开启。

3.6 一张图看懂证书链验证流程

下面这张图,展示了完整的证书链验证过程。你可以看到,如果中间证书缺失,验证会在哪一步卡住。

证书链验证流程 客户端(浏览器) 服务器 发起 TLS 握手 返回服务器证书(可能缺少中间证书) 验证证书链 证书链完整 → 建立安全连接 证书链不完整 → NET::ERR_CERT_AUTHORITY_INVALID 常见原因 • 服务器未配置中间证书 • 证书链文件顺序错误 • CDN 未传递中间证书 • 使用了自签名证书

3.7 避坑指南

最后,分享几个我踩过的坑:

  • 我曾经以为把根证书也加进去会更安全,结果导致某些旧版浏览器报错。记住,根证书不需要加。
  • 我曾经在 Nginx 里配了 ssl_trusted_certificate,以为这就是证书链。其实这个指令只用于 OCSP Stapling,不用于发送证书链。
  • 我建议每次更新证书后,都用 openssl s_client 验证一下。别等到用户投诉了才去查。

嗯,不完整证书链这个问题,说难不难,说简单也不简单。关键是理解原理,然后养成验证的习惯。下次再看到 NET::ERR_CERT_AUTHORITY_INVALID,你应该知道从哪里下手了。