エラーメッセージ
[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 サーバーなどです。
発生する理由
平文の HTTP ポートに https:// で接続している
よくある開発用サーバー、TLS を終端するロードバランサーの背後にある社内サービス、メトリクスのエンドポイントは、平文の HTTP で待ち受けていることがよくあります。それらのポートに https:// を使うと、すぐにこのエラーが発生します。
プロキシが https:// で設定されているが、HTTP で通信している
よくあるHTTPS_PROXY=https://proxy:3128 や proxies={"https": "https://…"} を指定すると、urllib3 はプロキシとの間で TLS を開始します。urllib3 1.26 以降はこの指定が文字どおりに扱われますが、ほとんどの企業向けプロキシは、クライアントからの平文の HTTP しか受け付けません。
STARTTLS のポートで smtplib.SMTP_SSL を使っている
よくある587 番ポート(と 25 番)は平文で始まり、STARTTLS でアップグレードします。暗黙的 TLS は 465 番です。587 番に対して SMTP_SSL を使うとこのエラーで失敗し、143 番に対して IMAP4_SSL を使った場合も同様です。
キャプティブポータルやフィルターが平文の HTTP で応答している
ときどきホテルやゲスト用の Wi-Fi、一部のセキュリティアプライアンスは、接続を横取りして HTTP のページを返します。
修正方法
- 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.
プロキシの 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.
メール:ポートに合ったクラスを使う
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()
関連するエラー
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)