错误信息
unable to verify the first certificate
也可能输出为
- code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
- UNABLE_TO_VERIFY_LEAF_SIGNATURE
较新的 Node.js 版本(我们测试的是 24.22)会在这条消息后追加“; if the root CA is installed locally, try running Node.js with --use-system-ca”。使用 fetch() 时,它作为“TypeError: fetch failed”的原因出现;axios 和 got 则把它显示为错误信息,代码相同。
Node.js tls / https / fetch — code UNABLE_TO_VERIFY_LEAF_SIGNATURE (OpenSSL X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, 21)
含义
Node.js 只收到了服务器自己的证书(叶子证书),并且在任何地方都找不到它的颁发者:握手中没有,受信任的根证书中也没有。没有颁发者,它甚至无法检查叶子证书的签名,所以消息里说的是“the first certificate”。几乎总是服务器忘了发送中间证书;浏览器会下载中间证书,从而掩盖这个问题,而 Node.js 从不这样做。
原因
服务器没有发送中间证书
常见证书文件中只有叶子证书(用了 cert.pem 而不是 fullchain.pem,或者上传到负载均衡器的证书没有附带证书链)。如复现所示,即使信任了正确的根证书,Node.js 也无法把叶子证书和根证书衔接起来。
叶子证书由私有 CA 签发,且证书链中没有任何已知证书
常见内部服务如果单独提供来自公司 CA 或自建 CA 的证书,也会报出同样的错误码:Node.js 既不认识颁发者,也不认识它上面的任何证书。
中间证书在文件中,但没有被使用
偶见有些服务器只发送文件中的第一张证书,或者要求在单独的设置中配置证书链(旧版 Apache 的 SSLCertificateChainFile,云负载均衡器中单独的证书链字段)。中间证书在磁盘上,却从未到达客户端。
修复方法
- 1.
检查服务器发送了几张证书
如果只出现深度 0,且其颁发者是中间 CA,就应该在服务器上修复。
bash openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' # Only " 0 s:" present, with an i: that is an intermediate -> the server must send that intermediate - 2.
提供完整证书链
为服务器配置一个证书包:先是叶子证书,后面依次跟着所有中间证书。对 Node.js 服务器来说是 cert 选项;对 nginx 是 ssl_certificate;对云负载均衡器是证书链字段。
js // Node.js HTTPS server: pass leaf + intermediates as the cert import https from "node:https"; import fs from "node:fs"; https.createServer({ key: fs.readFileSync("server.key"), cert: fs.readFileSync("fullchain.pem"), // leaf first, then intermediate(s) }, handler).listen(443); - 3.
如果无法修改服务器:在客户端添加中间证书
NODE_EXTRA_CA_CERTS 也接受中间证书,并在进程启动时读取一次。优先修复服务器:其他所有客户端(移动应用、合作伙伴)都有同样的问题。
bash # When you cannot fix the server: trust the missing intermediate on the client too NODE_EXTRA_CA_CERTS=/etc/ssl/certs/issuing-ca.pem node app.js - 4.
临时诊断:在单次运行中禁用验证
NODE_TLS_REJECT_UNAUTHORIZED=0 会关闭进程中所有 TLS 连接的证书检查,并打印一条警告。只用它来确认诊断;在生产环境中,它会让传输路径上的任何人都能读取和篡改流量。
bash # Temporary diagnostic only: disables certificate verification for the whole process NODE_TLS_REJECT_UNAUTHORIZED=0 node app.js
相关错误
unable to get local issuer certificateNode.js tls / https / fetchself-signed certificate in certificate chainNode.js tls / https / fetchnpm error code UNABLE_TO_VERIFY_LEAF_SIGNATUREnpm (Node.js)verify error:num=21:unable to verify the first certificateOpenSSL CLI (openssl s_client)curl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)