Mensagem de erro
code: 'ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE'
Também aparece como
- ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE
O código reflete a string de motivo do OpenSSL: versões do Node.js que embutem o OpenSSL 3.0 ou 3.1 informam ERR_SSL_SSLV3_ALERT_HANDSHAKE_FAILURE (de “sslv3 alert handshake failure”); as versões atuais, com OpenSSL 3.5, informam ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE. Com https.request(), o mesmo alerta aparece como “write EPROTO … SSL alert number 40”.
Node.js tls.connect / fetch — TLS alert 40 (handshake_failure) received from the server
O que significa
O servidor respondeu ao ClientHello do Node.js com o alerta TLS 40 (handshake_failure) e fechou a conexão. Ele não encontrou nenhuma combinação aceitável de cipher suite, grupo de troca de chaves e algoritmo de assinatura, ou exige um certificado de cliente que não foi enviado. O Node.js deriva o código de erro do texto de motivo do OpenSSL, e é por isso que ele contém “SSL/TLS”.
Por que acontece
Nenhuma cipher suite em comum
comumServidores antigos, restritos a cipher suites com troca de chaves RSA, com 3DES ou com RC4, esbarram na lista padrão de cifras do Node.js, que não as inclui mais.
O servidor exige um certificado de cliente (mTLS)
comumAPIs de pagamento, bancárias e B2B muitas vezes exigem TLS mútuo; sem cert e key no agente, servidores TLS 1.2 abortam com handshake_failure.
SNI ausente ou desconhecido
ocasionalConectar a um endereço IP sem servername, ou a um nome que a CDN não atende, faz alguns front-ends rejeitarem o handshake.
Como corrigir
- 1.
Comparar o que os dois lados aceitam
Imprima a lista padrão de cifras do Node.js e enumere as cipher suites do servidor; se não houver nenhuma em comum, o servidor precisa ser atualizado.
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.
Enviar o certificado de cliente
Configure cert e key (ou pfx) no agente usado para o endpoint mTLS.
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.
Donos do servidor: oferecer cipher suites atuais
O TLS 1.3 mais o TLS 1.2 com ECDHE e AES-GCM ou ChaCha20-Poly1305 funcionam com todas as versões do Node.js que ainda recebem manutenção.
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;
Erros relacionados
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)