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

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

Hostname/IP does not match certificate's altnames: Host: api.example.com. is not in the cert's altnames: DNS:www.example.com

Также выводится как

  • Hostname/IP does not match certificate's altnames: IP: 127.0.0.1 is not in the cert's list:
  • code: 'ERR_TLS_CERT_ALTNAME_INVALID'
  • ERR_TLS_CERT_ALTNAME_INVALID

Хост и список altnames в каждом случае свои. Для IP-адресов формулировка такая: «Hostname/IP does not match certificate's altnames: IP: <address> is not in the cert's list: <entries>». npm выводит эту ошибку как «npm error code ERR_TLS_CERT_ALTNAME_INVALID».

Node.js tls.checkServerIdentity() — code ERR_TLS_CERT_ALTNAME_INVALID

Что это означает

Цепочка сертификатов признана доверенной, но tls.checkServerIdentity() не нашла ни одного альтернативного имени субъекта (SAN), совпадающего с хостом, к которому подключился Node.js. В сообщении указаны обе стороны: хост, который вы запросили, и имена, которые на самом деле содержит сертификат, поэтому несоответствие видно сразу. Общее имя (CN) игнорируется, если в сертификате есть расширение SAN.

Почему это происходит

Как исправить

  1. 1.

    Посмотрите имена в сертификате

    Сравните subjectAltName с хостом, к которому подключаетесь.

    bash
    echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \
      | openssl x509 -noout -ext subjectAltName
  2. 2.

    Перевыпустите сертификат со всеми используемыми именами

    Добавьте все DNS-имена, а если клиенты подключаются по адресу, то и записи типа IP.

    bash
    openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \
      -addext "subjectAltName=DNS:api.example.com,DNS:www.example.com,IP:10.0.0.5"
  3. 3.

    Задавайте servername при подключении по адресу

    Укажите имя из сертификата в servername (и в заголовке Host), а подключайтесь по адресу; тогда проверка идёт по правильному имени, а не отключается.

    js
    // Connect to an address but verify the certificate's real name (also sent as SNI)
    import https from "node:https";
    
    https.get({ host: "10.0.0.5", port: 443, path: "/", servername: "api.example.com",
                headers: { host: "api.example.com" } }, (res) => res.resume());
  4. 4.

    Точечное исключение через checkServerIdentity

    Для устаревшего хоста, сертификат которого пока нельзя перевыпустить, сопоставьте один известный псевдоним с именем из сертификата и передайте проверку в tls.checkServerIdentity(). Никогда не возвращайте undefined безусловно: это полностью отключает проверку имени.

    js
    // Narrow exception for a host you cannot reissue: accept one extra name, keep all other checks
    import https from "node:https";
    import tls from "node:tls";
    
    const agent = new https.Agent({
      checkServerIdentity: (host, cert) =>
        tls.checkServerIdentity(host === "legacy-alias.internal" ? "api.example.com" : host, cert),
    });

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

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