TLS 证书链:浏览器到底在信谁
证书配了还报错,多数时候不是证书本身有问题,是这条链走不到客户端信任的那个根。
现象:证书配了,浏览器仍报错
四种原因要先分开:域名不匹配、时间不对、链不完整、SNI 没对上。四种对应四类现象,混在一起查,只会来回换证书。
浏览器信的不是"证书里写了这个域名",是"这条链能走到受信根、且这张证书确实签给这个域名"。 链断在哪,报错就在哪。
根、中间、叶:三段,缺一段都不行
| 段 | 谁签发 | 谁持有 | 该不该由服务器下发 |
|---|---|---|---|
| 叶(服务器证书) | 中间 CA | 服务器 | 是 |
| 中间 CA | 根或上一级中间 | 服务器 | 是,按顺序附在叶后面 |
| 根 CA | 自签 | 客户端信任库 | 否 |
叶证书绑域名与公钥,由中间签;中间由根签;根自签,预置在操作系统或浏览器的信任库里。
服务器该发的是"叶 + 中间"。下发根是常见错误:客户端本来就有,多发一张只增加握手字节;更要紧的是根换过(交叉签名)时,下发的旧根还可能让部分客户端的路径构建选到旧根,反而断掉。
浏览器校验顺序:报错对应哪一步
- 链能否逐级验签到信任库里的某个根。
- 叶上的 SAN 是否匹配当前主机名。
- 有效期区间是否覆盖当前时间。
- 用途与约束:叶要有 serverAuth,中间要标 CA。
- 吊销状态:CRL 或 OCSP,吊销检查多为软失败。
这五步是排查顺序,不是浏览器内部严格串行的流水线;实际实现会把链、时间、用途放在同一次路径校验里,报错优先级也因实现而异。
| 报错 | 断在哪一步 | 下一步看什么 |
|---|---|---|
证书颁发机构无效(ERR_CERT_AUTHORITY_INVALID) | 第 1 步 | 链里有几张、缺不缺中间、根是否在信任库 |
域名不匹配(ERR_CERT_COMMON_NAME_INVALID) | 第 2 步 | 叶的 SAN 有没有当前主机 |
证书过期或未生效(ERR_CERT_DATE_INVALID) | 第 3 步 | 叶与中间的有效期、客户端时钟 |
| 协议错误 | 不在证书 | 端口、协议版本、握手是否被打断 |
常见故障:四个高频
- 缺中间证书:服务器只发了叶。浏览器报链错,而部分客户端会顺着叶里的 AIA 地址自己去取中间,取到就正常——同一张证书一半人能用、一半人报错,最容易误判成"证书没问题"。
- SNI 没对上:一张证书按 SNI 选择返回,不带 SNI 抓到的是默认站点证书。拿默认站点的证书判断"配错了",判断本身就是错的。
- 时间不对:证书过期,或客户端时钟漂移。内网设备时钟跑偏是高频原因。
- 自签证书:链走不到公共根。内网该做的是把自有根预置进客户端,不是让使用者习惯性点"继续"。
怎么看出链断在哪:三条命令
# 带 SNI 拿服务器实际下发的整条链
openssl s_client -showcerts -servername example.com -connect example.com:443
# 用本地信任库单独验一次,定位断在哪一级
openssl verify -CAfile ca.pem -untrusted int.pem leaf.pem
# 从客户端视角看握手与校验结论
curl -vI https://example.com
第一条输出里的 Certificate chain 是服务器实际发送的顺序,先数几段,再看结尾那行校验结论:
verify error:num=20:unable to get local issuer certificate
这句通常意味着本地链断在"找不到签发者":多数是缺中间,也可能是根不在本地信任库。第二条命令能把断点落到具体一级;第三条给出客户端最终结论,三条命令的结论对不上,问题就在链,不在密钥。
内网与自签证书的正确用法
建一条自己的链:离线保存根,用中间签业务证书,把根通过 MDM、组策略或镜像预置进客户端信任库,叶上写正确的 SAN,并给根与中间设有效期。
三条纪律:根不下发、中间不省略、私钥不进代码仓库。根的有效期长、中间的有效期短,中间轮换要留重叠期,否则换证当天会断一批客户端。
校验不是可以被"跳过"的开关,它是一条链的完整性检查。 把它关掉,问题不会消失,只会从可见变成不可见。
链路视角见攻击链路;客户端信任库与证书存储见操作系统底层;握手在组件里怎么落地见组件解析。
本文仅用于安全学习与授权环境下的测试。文中所有示例均为本地或授权靶场环境,不构成对任何真实系统的测试指引。
仅限授权测试,严禁非法滥用。
读到这里,说明你在认真看。加入社群,与我们一起深挖底层。
或点此直接进入「星巡底层研习」 →
扫码加入交流社群