报错里带 certificate、SSL handshake、verify 这几个字样的,先别急着骂对方服务器。证书接口调用失败这类问题,我这些年遇到的,大部分跟网络一点关系都没有,是信任链没凑齐——中间少一张证书,或者客户端压根不认签发它的那个 CA。链这玩意儿平时没人看,断了才知道疼。

证书接口调用失败?先分清连不上还是验不过
这两个方向差得远。curl 报 connection refused、timeout,那是 TCP 层就没通,该去查防火墙、安全组、端口、白名单。可要是报 curl: (60) SSL certificate problem: unable to get local issuer certificate,或者 Java 那边甩一句 PKIX path building failed,说明路已经通了,是握手阶段对方把证书递过来,你这边验不过。前者修网络,后者修信任,方向搞错了折腾一晚上也白搭。见过有人把安全组端口翻来覆去查了三遍,最后发现日志里那句 verify error 从头到尾都在。
信任链就是一张介绍信
打开浏览器点小锁,能看到证书的层级:最上面是根 CA,中间一层是中间 CA,最下面才是域名自己那张叶子证书。客户端为什么敢信叶子?因为它信根,根签了中间,中间签了叶子,一环扣一环。麻烦在于,服务器握手时通常只把叶子证书发出来,中间那几张得自己带上。客户端本地有个根证书库,根它有,中间它没有,链就断在半截。有的中间 CA 还被交叉签名过,链上可能多出一两张,数的时候别嫌它乱,那是人家给你留的备胎。
服务器只发半截链,是最常见的一种
验证方法很简单,一条命令:openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts。看两处。一是 Verify return code,20 就是 unable to get local issuer certificate,21 是链上某张过期,19 是自签。二是返回的证书张数,正常至少两张:叶子加中间。只有一张,基本就确诊了。补的办法是把 fullchain.pem 配上去,顺序别搞反,服务器证书在前,中间证书跟在后面,根证书不要塞进去——塞了有些客户端反而嫌你多事。老版本 nginx 里还有 ssl_certificate_chain_file 这个单独写法,两个文件都得指对。
客户端那头的根库,旧起来真要命
还有一种情况:服务器链发得挺全,换台机器一测就过,唯独线上那台报错。这时候多半是客户端自己的根证书库太老。早些年装的系统镜像、几年前的 JDK,根库里停在那时候的 CA 列表,人家新换的中间 CA 它当然不认。处理路子:系统层面 update-ca-certificates,Java 的话往 $JAVA_HOME/lib/security/cacerts 里用 keytool 导,Python 的 requests 走 certifi,Node 还能用 NODE_EXTRA_CA_CERTS 指一个 pem 进去。别嫌麻烦,这一步比改业务代码靠谱得多。
中间夹了代理、CDN、负载均衡,链会被谁换掉
线上很少是浏览器直连源站。nginx 做反代的时候,proxy_ssl_verify 默认是关的,所以你看着好像在验证,实际上啥也没验;真开了,还得配 proxy_ssl_trusted_certificate 和 proxy_ssl_server_name,少一样就验不过。走 CDN 的,CDN 节点回源也要握手,源站链不全,边缘就回 5xx 或者那种 526 类的回源 SSL 错误,你在本地怎么测都是好的,只剩一脸问号。负载均衡把 TLS 卸载掉、后端走明文 http 的,日志里看到的错误跟证书根本没关系,别被带偏。
印象最深的一次,一个接口在办公室跑得好好的,搬到机房就挂,折腾了大半天,最后发现机器上那个 nginx 配的是老写法:ssl_certificate 指向的是只有叶子证书的 crt,另一个 chain 文件没配。文件都在服务器上躺着,就是没用上。
双向认证、自签证书,报错长得不一样
双向认证的接口,除了服务器证书,还得看客户端那张。客户端证书没配、或者它自己链不全,报出来的常常是 handshake failure,或者 alert certificate required,压根不直接提证书的事,容易看懵。自签证书的报错则是 self signed certificate in certificate chain 或者 unable to verify the first certificate。测试环境自签很普遍,开发图省事在代码里加个跳过校验的开关,上线忘了摘,链的问题就被彻底藏起来了——这比天天报错还危险。
顺带提一句,系统时间不对这条最冤。客户端机器时间差得多,证书的生效期、过期期一算全乱,报错跟链断了几乎一模一样。date 看一眼,NTP 对一下,两分钟的事,别一头扎进证书文件里翻半天。
按这个顺序走,十分钟能定位
① 分辨连不上还是验不过;② 拿 s_client 看 verify code 和返回张数;③ 数证书,缺中间就补 fullchain;④ 换个语言、换台机器试试,能过就是客户端根库的问题;⑤ date 看时间;⑥ 一层层往上排:本地、反代、CDN 回源、后端;⑦ 最后才怀疑对方换了证书或者换了 CA——这个概率最低,但确实有,真遇上就去翻对方公告,以官方说明为准。
链这东西出问题,通常不是全断,是断一环。把叶子、中间、根这几张数清楚,比在代码里加十行重试有用。下次再看到证书接口调用失败的报错,先敲那条 s_client,答案基本都在 verify 那几行里。
【版权声明】:本站内容若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!