跳到主要内容
ecdsa.com
Node.js tls.connect / fetchNode.js crypto 模块

错误信息

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

含义

服务器用 TLS 告警 40(handshake_failure)回应了 Node.js 的 ClientHello,并关闭了连接。它找不到可接受的密码套件、密钥交换组和签名算法组合,或者要求提供客户端证书,而客户端没有发送。Node.js 根据 OpenSSL 的原因文本生成错误代码,因此代码中含有“SSL/TLS”。

原因

修复方法

  1. 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. 2.

    发送客户端证书

    在用于该 mTLS 端点的 Agent 上配置 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. 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;

相关错误

浏览完整的签名错误库