Перейти к содержимому
ecdsa.com
Node.js tls / https / fetchМодуль crypto в Node.js

Сообщение об ошибке

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 получил только собственный (конечный) сертификат сервера и нигде не нашёл его издателя: ни в рукопожатии, ни среди доверенных корневых сертификатов. Без издателя 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

Связанные ошибки

Открыть всю базу ошибок подписей