本文へスキップ
ecdsa.com
Node.js tls.checkServerIdentity()Node.js の crypto

エラーメッセージ

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() は、Node.js の接続先ホストに一致するサブジェクト代替名を見つけられませんでした。メッセージには、要求したホストと、証明書に実際に含まれる名前の両方が示されるため、不一致はひと目でわかります。証明書に 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 で範囲を絞った例外を設ける

    証明書をまだ再発行できないレガシーなホストでは、既知のエイリアス 1 つを証明書の名前に対応付けてから、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),
    });

関連するエラー

署名エラーデータベースをすべて見る