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

エラーメッセージ

[SSL: WRONG_VERSION_NUMBER] wrong version number

別の表記

  • ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number

その後に「(_ssl.c:1082)」のようなソースの位置が続きます。urllib では「<urlopen error …>」の中に、requests と urllib3 では「Max retries exceeded … (Caused by SSLError(…))」の中に表示されます。

Python ssl module (OpenSSL) — ssl.SSLError, SSL_R_WRONG_VERSION_NUMBER

このエラーの意味

Python が TLS ハンドシェイクを開始しましたが、返ってきたバイト列は TLS レコードではありませんでした。OpenSSL はそれをレコードヘッダーとして読み取り、ありえないプロトコルバージョンだと判断します。実際には、相手側がそのポートで平文で通信しています。HTTP サーバー、平文の HTTP を想定しているプロキシ、STARTTLS の前にグリーティングのやり取りを待っている SMTP サーバーなどです。

発生する理由

修正方法

  1. 1.

    ポートが何のプロトコルで通信しているかを確認する

    http:// でポートにリクエストを送り、openssl s_client で TLS ハンドシェイクを試してください。その結果に合ったスキームか、正しいポートを使ってください。

    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. 2.

    プロキシの URL は http:// で記述する

    proxies マッピングの https エントリは、HTTPS の宛先に使うプロキシを指定するものです。その URL のスキームは、プロキシ自体とどう通信するかを表します。宛先との通信は、それでもエンドツーエンドの TLS のままです。

    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. 3.

    メール:ポートに合ったクラスを使う

    587 番では SMTP + starttls() を、465 番では SMTP_SSL を使ってください。同じルールは imaplib と 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()

関連するエラー

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