エラーメッセージ
code: 'ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE'
別の表記
- ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE
コードは OpenSSL の理由文字列をそのまま反映しています。OpenSSL 3.0 または 3.1 を同梱した Node.js のリリースは ERR_SSL_SSLV3_ALERT_HANDSHAKE_FAILURE(「sslv3 alert handshake failure」に由来)を報告し、OpenSSL 3.5 を同梱した現行のリリースは ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE を報告します。https.request() では、同じアラートが「write EPROTO … SSL alert number 40」として現れます。
Node.js tls.connect / fetch — TLS alert 40 (handshake_failure) received from the server
このエラーの意味
サーバーは Node.js の ClientHello に TLS アラート 40(handshake_failure)で応答し、接続を閉じました。暗号スイート、鍵交換グループ、署名アルゴリズムの受け入れ可能な組み合わせが見つからなかったか、送信されなかったクライアント証明書をサーバーが要求しているかのどちらかです。Node.js はエラーコードを OpenSSL の理由テキストから生成するため、コードに「SSL/TLS」が含まれています。
発生する理由
共通の暗号スイートがない
よくあるRSA 鍵交換、3DES、RC4 のいずれかを使う暗号スイートしか提示できない古いサーバーの場合、Node.js のデフォルトの暗号リストには、これらのスイートがもう含まれていません。
サーバーがクライアント証明書(mTLS)を要求している
よくある決済、銀行、B2B の API では、相互 TLS が必須なことがよくあります。エージェントに cert と key が設定されていないと、TLS 1.2 のサーバーは handshake_failure でハンドシェイクを中止します。
SNI がない、または認識されない
ときどきservername を指定せずに IP アドレスに接続したり、CDN が提供していない名前に接続したりすると、一部のフロントエンドはハンドシェイクを拒否します。
修正方法
- 1.
双方が対応しているものを比較する
Node.js のデフォルトの暗号リストを出力し、サーバーの暗号スイートを列挙してください。重なりがなければ、サーバーを更新しなければなりません。
bash node -p "require('tls').getCiphers().length + ' suites; default list: ' + require('tls').DEFAULT_CIPHERS" nmap --script ssl-enum-ciphers -p 443 api.example.com # what the server accepts - 2.
クライアント証明書を送信する
mTLS のエンドポイントに使うエージェントに、cert と key(または pfx)を設定してください。
js // Mutual TLS: present the client certificate the server requires import https from "node:https"; import fs from "node:fs"; const agent = new https.Agent({ cert: fs.readFileSync("client.pem"), key: fs.readFileSync("client.key") }); https.get("https://mtls.example.com/", { agent }, (res) => res.resume()); - 3.
サーバー管理者:現行の暗号スイートを提供する
TLS 1.3 に加えて、ECDHE と AES-GCM または ChaCha20-Poly1305 を使う TLS 1.2 を提供すれば、サポートが継続しているすべての Node.js のリリースで動作します。
text # Server side (nginx): TLS 1.3 + TLS 1.2 ECDHE with AEAD ciphers ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
関連するエラー
curl: (35) TLS connect error: error:0A000410:SSL routines::ssl/tls alert handsh…curl (OpenSSL backend)SSL routines:ssl3_read_bytes:ssl/tls alert handshake failureOpenSSL (client side)[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failurePython ssl module (OpenSSL)javax.net.ssl.SSLHandshakeException: (handshake_failure) Received fatal alert:…Java (JSSE)