跳到主要内容
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()

相关错误

浏览完整的签名错误库