本文へスキップ
ecdsa.com
Python ssl module (OpenSSL)Python の cryptography

エラーメッセージ

[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol

別の表記

  • ssl.SSLEOFError: EOF occurred in violation of protocol

OpenSSL 3 では、Python は理由コード「[SSL: UNEXPECTED_EOF_WHILE_READING]」を表示します。OpenSSL 1.1.1 では、テキストは「EOF occurred in violation of protocol」だけです。その後に「(_ssl.c:1082)」のようなソースの位置が続きます。

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

このエラーの意味

Python がまだ TLS ハンドシェイク中(またはデータの読み取り中)に、相手側が TLS アラートも close_notify も送信せずに TCP 接続を閉じました。OpenSSL は、この通知なしの切断をプロトコル違反として扱います。Python には相手が切断した理由はわかりません。原因はサーバー、プロキシ、または途中にあるファイアウォールにあります。

発生する理由

修正方法

  1. 1.

    openssl s_client でハンドシェイクを再現する

    s_client でも切断される場合は、SNI と TLS のバージョンを変えて、サーバーが何を拒否しているかを確認してください。s_client で成功する場合は、その設定を Python クライアントの設定(プロキシ、SNI、バージョン)と比較してください。

    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.

    プロキシの環境変数を確認する

    requests、urllib、pip は HTTPS_PROXY と NO_PROXY に従います。プロキシ URL のスキームを修正し、直接接続しなければならない社内ホストを除外してください。

    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.

    原因が一時的な場合はリトライする

    レート制限や不安定なネットワークに対しては、バックオフ付きのリトライによって、散発的なリセットを、時間はかかっても成功に変えられます。ただし、常にハンドシェイクを拒否するサーバーは、リトライでは解決しません。

    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/")

関連するエラー

署名エラーデータベースをすべて見る