错误信息
[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)