Pular para o conteúdo
ecdsa.com
Python ssl module (OpenSSL)Python (cryptography)

Mensagem de erro

[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol

Também aparece como

  • ssl.SSLEOFError: EOF occurred in violation of protocol

Com o OpenSSL 3, o Python mostra o código de motivo “[SSL: UNEXPECTED_EOF_WHILE_READING]”; com o OpenSSL 1.1.1, o texto é só “EOF occurred in violation of protocol”. Em seguida vem uma localização no código-fonte, como “(_ssl.c:1082)”.

Python ssl module (OpenSSL) — ssl.SSLEOFError, SSL_R_UNEXPECTED_EOF_WHILE_READING

O que significa

O outro lado fechou a conexão TCP enquanto o Python ainda estava no handshake TLS (ou no meio da leitura de dados), sem enviar um alerta TLS nem close_notify. O OpenSSL trata esse encerramento silencioso como violação do protocolo. O Python não tem como saber por que o peer saiu; o motivo está no servidor, em um proxy ou em um firewall no caminho.

Por que acontece

Como corrigir

  1. 1.

    Reproduzir o handshake com openssl s_client

    Se o s_client também for desconectado, varie o SNI e a versão do TLS para ver o que o servidor rejeita; se o s_client funcionar, compare as configurações dele com as do seu cliente Python (proxy, SNI, versões).

    bash
    # Does a plain OpenSSL handshake work from the same machine?
    openssl s_client -connect api.example.com:443 -servername api.example.com -brief </dev/null
    # Without SNI, and pinned to TLS 1.2, to see what the server objects to
    openssl s_client -connect api.example.com:443 -noservername -brief </dev/null
    openssl s_client -connect api.example.com:443 -servername api.example.com -tls1_2 -brief </dev/null
  2. 2.

    Verificar as variáveis de ambiente de proxy

    O requests, o urllib e o pip respeitam HTTPS_PROXY e NO_PROXY. Corrija o esquema da URL do proxy e exclua os hosts internos que precisam ser acessados diretamente.

    bash
    env | grep -i -E '^(https?|no|all)_proxy='
    # Proxy URLs should normally be http:// (CONNECT tunnel), and internal hosts listed in NO_PROXY
    export HTTPS_PROXY=http://proxy.example.net:3128
    export NO_PROXY=localhost,127.0.0.1,.internal.example.com
  3. 3.

    Tentar de novo quando a causa é passageira

    Com limitação de taxa e redes instáveis, novas tentativas com intervalo crescente (backoff) transformam quedas esporádicas em sucessos mais lentos; elas não corrigem um servidor que sempre recusa o handshake.

    python
    import requests
    from requests.adapters import HTTPAdapter
    from urllib3.util.retry import Retry
    
    session = requests.Session()
    session.mount("https://", HTTPAdapter(max_retries=Retry(total=3, backoff_factor=1)))
    session.get("https://api.example.com/")

Erros relacionados

Ver toda a base de erros de assinatura