跳到主要内容
ecdsa.com
Node.js tls / https / fetchNode.js crypto 模块

错误信息

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 从不这样做。

原因

修复方法

  1. 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. 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. 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. 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

相关错误

浏览完整的签名错误库