エラーメッセージ
self-signed certificate in certificate chain
別の表記
- code: 'SELF_SIGNED_CERT_IN_CHAIN'
- SELF_SIGNED_CERT_IN_CHAIN
Node.js 16 以前(OpenSSL 1.1.1)では「self signed certificate in certificate chain」と表記されていました。fetch() では「TypeError: fetch failed」の原因として現れ、npm は「npm error code SELF_SIGNED_CERT_IN_CHAIN」と出力します。
Node.js tls / https / fetch — code SELF_SIGNED_CERT_IN_CHAIN (OpenSSL X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, 19)
このエラーの意味
サーバーが送信したチェーンは、Node.js が信頼するルートに含まれていない自己署名のルート証明書で終わっています。社内ネットワークでは、これは TLS を検査するプロキシの典型的な痕跡です。そのプロキシはすべてのサイトの証明書を独自のルートで署名し直し、そのルートをチェーンに含めます。Node.js が使うのは同梱の Mozilla のルートリストであり、IT 部門がプロキシのルートをインストールした OS のストアではありません。
発生する理由
TLS を検査するプロキシやウイルス対策ソフト
よくあるZscaler、Netskope、Fortinet、Palo Alto や、HTTPS をスキャンするウイルス対策製品は、独自のルートを提示します。ブラウザーは OS のストアを通じてそのルートを信頼しますが、Node.js はデフォルトでは信頼しません。
プライベートなサービスが独自のルートを送信している
よくある社内のルートをチェーンに含めている社内サーバーであっても、クライアント側でそのルートを信頼させる必要があります。ルートを送信しても、何の証明にもなりません。
ルートは OS にインストールされているが、Node.js は独自のリストを使っている
ときどきNode.js は Mozilla のルートをバイナリに同梱しており、--use-system-ca または NODE_USE_SYSTEM_CA=1 を設定しない限り、システムのストアを無視します。
修正方法
- 1.
チェーンの発行者を確認する
公開サイトに接続して、相手の証明書チェーンをたどってください。最上位の証明書に自社名やセキュリティベンダーの名前が付いていれば、そのルートを信頼してください。見覚えのない名前であれば、何かを信頼する前に調査してください。
bash openssl s_client -connect registry.npmjs.org:443 -servername registry.npmjs.org -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' # The last line pair shows the root the chain ends in (s: and i: identical) - 2.
NODE_EXTRA_CA_CERTS でルートを追加する
ファイル内の証明書は、npm、yarn、fetch を含むプロセスのすべての TLS 接続について、組み込みのルートに追加されます。プロセスの起動前に設定してください。
bash export NODE_EXTRA_CA_CERTS=/etc/ssl/private-ca/corp-proxy-root.pem node app.js - 3.
OS の証明書ストアを使う
--use-system-ca または NODE_USE_SYSTEM_CA=1 を指定すると、Node.js は OS が信頼するルートを受け入れるようになるため、IT 部門が配布したプロキシのルートが、ファイルをコピーしなくても機能します。
bash # Managed machines already trust the proxy root in the OS store node --use-system-ca app.js NODE_USE_SYSTEM_CA=1 npm run build - 4.
一時的な診断:NODE_TLS_REJECT_UNAUTHORIZED=0
プロセス全体で証明書の検証を無効にします。原因を確認するための 1 回の実行にだけ使ってください。傍受するプロキシの背後では、プロキシ以外の攻撃者がいても、その存在も見えなくなります。
bash # Temporary diagnostic only: confirms trust is the only problem, then remove it NODE_TLS_REJECT_UNAUTHORIZED=0 node app.js