Mensagem de erro
[SSL: WRONG_VERSION_NUMBER] wrong version number
Também aparece como
- ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number
Seguido de uma localização no código-fonte, como “(_ssl.c:1082)”. O urllib mostra o erro dentro de “<urlopen error …>”, e o requests e o urllib3, dentro de “Max retries exceeded … (Caused by SSLError(…))”.
Python ssl module (OpenSSL) — ssl.SSLError, SSL_R_WRONG_VERSION_NUMBER
O que significa
O Python iniciou um handshake TLS, e os bytes que voltaram não são um registro TLS: o OpenSSL os lê como um cabeçalho de registro com uma versão de protocolo impossível. Na prática, o outro lado fala texto claro nessa porta — um servidor HTTP, um proxy que espera HTTP não criptografado ou um servidor SMTP aguardando a troca de saudações antes do STARTTLS.
Por que acontece
https:// para uma porta que serve HTTP não criptografado
comumServidores de desenvolvimento, serviços internos atrás de um balanceador de carga que faz a terminação TLS e endpoints de métricas costumam escutar em HTTP não criptografado. Usar https:// com a porta deles produz este erro imediatamente.
O proxy está configurado como https://, mas fala HTTP
comumHTTPS_PROXY=https://proxy:3128 ou proxies={"https": "https://…"} fazem o urllib3 iniciar o TLS com o proxy. Desde o urllib3 1.26, isso é respeitado ao pé da letra, e a maioria dos proxies corporativos só aceita HTTP não criptografado dos clientes.
smtplib.SMTP_SSL em uma porta STARTTLS
comumA porta 587 (e a 25) começa em texto claro e passa para TLS com STARTTLS; o TLS implícito fica na 465. SMTP_SSL na 587 falha desse jeito, assim como IMAP4_SSL na 143.
Um portal cativo ou filtro responde em HTTP não criptografado
ocasionalRedes Wi-Fi de hotéis ou de visitantes e alguns equipamentos de segurança interceptam a conexão e respondem com uma página HTTP.
Como corrigir
- 1.
Descobrir o que a porta fala
Faça uma requisição à porta com http:// e tente um handshake TLS com openssl s_client; depois, use o esquema correspondente ou a porta correta.
bash curl -si http://127.0.0.1:8080/ | head -1 # an HTTP status line: the port is plain HTTP openssl s_client -connect 127.0.0.1:8443 -brief </dev/null # a TLS summary: the port speaks TLS - 2.
Escrever URLs de proxy com http://
A entrada https do mapeamento proxies indica o proxy para destinos HTTPS; o esquema da URL dela descreve como falar com o próprio proxy. O tráfego até o destino continua com TLS de ponta a ponta.
python import requests # Most forward proxies take plain HTTP from the client and tunnel TLS with CONNECT proxies = {"https": "http://proxy.example.net:3128"} # http:// here, not https:// requests.get("https://api.example.com/", proxies=proxies) - 3.
E-mail: escolher a classe de acordo com a porta
Use SMTP + starttls() na 587 e SMTP_SSL na 465; a mesma regra vale para o imaplib e o poplib.
python import smtplib, ssl ctx = ssl.create_default_context() # Port 587: plain connection first, then STARTTLS with smtplib.SMTP("mail.example.com", 587) as s: s.starttls(context=ctx) # Port 465: implicit TLS from the first byte with smtplib.SMTP_SSL("mail.example.com", 465, context=ctx) as s: s.noop()
Erros relacionados
curl: (35) TLS connect error: error:0A00010B:SSL routines::wrong version numbercurl (OpenSSL backend)SSL routines:tls_validate_record_header:wrong version numberOpenSSL 3 (openssl s_client and any OpenSSL-based client)code: 'ERR_SSL_WRONG_VERSION_NUMBER'Node.js tls.connect / fetch (undici)[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocolPython ssl module (OpenSSL)