Mensagem de erro
[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failure
Também aparece como
- [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure
O código de motivo continua SSLV3_ALERT_HANDSHAKE_FAILURE, mas o texto depende do OpenSSL: “ssl/tls alert handshake failure” com o OpenSSL 3.3 e posteriores, “sslv3 alert handshake failure” com versões anteriores. Em seguida vem uma localização no código-fonte, como “(_ssl.c:1082)”.
Python ssl module (OpenSSL) — ssl.SSLError, TLS alert 40 (handshake_failure) from the server
O que significa
O servidor abortou o handshake com o alerta TLS 40 (handshake_failure). Ele não encontrou parâmetros aceitáveis no ClientHello do Python ou exigia um certificado de cliente que não foi apresentado. O alerta em si não traz detalhes, então a causa precisa ser descoberta comparando o que cada lado aceita ou lendo o log do servidor.
Por que acontece
Nenhuma cipher suite em comum
comumDesde o Python 3.10, o contexto padrão não oferece nenhuma cipher suite sem forward secrecy nem nenhuma com MAC SHA-1, no nível de segurança 2 do OpenSSL. Servidores legados restritos a cipher suites com troca de chaves RSA, com CBC-SHA ou com 3DES não têm nada em comum com ele.
O servidor exige um certificado de cliente
comumEndpoints com TLS mútuo (APIs bancárias e B2B, serviços internos) respondem com este alerta a um handshake sem certificado de cliente no TLS 1.2.
SNI ausente ou não configurado no servidor
ocasionalConectar por IP sem server_hostname, ou a um nome que a CDN ou o proxy não atende, faz alguns servidores abortarem com handshake_failure.
Como corrigir
- 1.
Comparar as listas de cifras
Imprima o que este Python oferece e compare com a lista de cifras do servidor (obtida, por exemplo, com nmap --script ssl-enum-ciphers). Se não houver interseção, o servidor precisa ser atualizado.
python import ssl ctx = ssl.create_default_context() print(sorted(c["name"] for c in ctx.get_ciphers())) # what this Python offers (TLS 1.2 names) - 2.
Apresentar o certificado de cliente
Para APIs com mTLS, carregue o certificado de cliente e a chave no contexto com load_cert_chain(); o requests aceita cert=("client.pem", "client.key").
python import ssl, urllib.request ctx = ssl.create_default_context() ctx.load_cert_chain(certfile="client.pem", keyfile="client.key") # mutual TLS urllib.request.urlopen("https://mtls.example.com/", context=ctx) - 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 são aceitos por todos os clientes que ainda recebem manutenção.
text # Server side: offer TLS 1.3 and TLS 1.2 ECDHE + AEAD suites 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;