错误信息
curl: (35) TLS connect error: error:0A00010B:SSL routines::wrong version number
也可能输出为
- curl: (35) error:0A00010B:SSL routines::wrong version number
- curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number
较新的 curl 版本(此处为 8.14.1)会在 OpenSSL 给出的原因前加上“TLS connect error: ”;curl 7.x 只打印原因本身。基于 OpenSSL 1.1.1 的构建会打印长格式“error:1408F10B:SSL routines:ssl3_get_record:wrong version number”;OpenSSL 3.x 打印的是“error:0A00010B:SSL routines::wrong version number”。
curl (OpenSSL backend) — CURLE_SSL_CONNECT_ERROR, SSL_R_WRONG_VERSION_NUMBER
含义
curl 发送了 TLS ClientHello,但返回的前几个字节并不是 TLS 记录。OpenSSL 从这个回复中读取记录头部的版本字段,读到的是乱码,通常是纯 HTTP 服务器返回的“HTTP/1.1 400”这几个字符。尽管措辞如此,这个错误几乎从来都与 TLS 版本无关:对方在那个端口上根本没有使用 TLS。
原因
在提供纯 HTTP 服务的端口上使用 https://
常见运行在 8080 或 3000 端口的开发服务器、负载均衡器后面的后端,或者配置错误的 listen 指令,都会用 HTTP 响应。在 URL 中把 http 和 https 弄反,或者对 TLS 端口号使用 http://,是这条消息最常见的来源。
代理 URL 写的是 https://,但代理使用的是 HTTP
常见HTTPS_PROXY=https://proxy:3128 会让 curl 与代理本身建立 TLS。大多数正向代理期望客户端发送纯 HTTP,再向目标打开加密的 CONNECT 隧道,因此即使是 HTTPS 流量,代理 URL 也应该以 http:// 开头。
对 STARTTLS 端口使用隐式 TLS
偶见25/587 端口上的 SMTP、143 端口上的 IMAP、110 端口上的 POP3、389 端口上的 LDAP,以及 PostgreSQL/MySQL,都先用明文问候,之后再升级。在这些端口上一开始就发起 TLS 握手会立即失败。
强制认证页面或过滤器代替服务器作出了响应
偶见酒店和机场 Wi-Fi、家长控制过滤器以及某些防火墙会拦截 443 端口,在任何 TLS 通信开始之前就返回 HTTP 重定向页面。
修复方法
- 1.
检查端口实际使用的协议
用 http:// 请求同一个端口。如果收到的是 HTTP 响应,要么改用 http://,要么改用真正的 TLS 端口;openssl s_client 可以确认哪些端口能完成 TLS 握手。
bash # What does the port speak? An HTTP status line means plain HTTP. curl -sS -i http://api.example.com:8080/ | head -1 # HTTP/1.1 200 OK -> not TLS openssl s_client -connect api.example.com:8443 -brief </dev/null # handshake summary -> TLS - 2.
代理 URL 使用 http://
除非你的代理明确支持客户端到代理之间的 TLS,否则把代理写成 http://host:port 的形式。到目标的连接仍然是通过 CONNECT 隧道的端到端 TLS。
bash # Most corporate proxies accept plain HTTP from the client and tunnel HTTPS with CONNECT export HTTPS_PROXY=http://proxy.example.net:3128 # http:// even for HTTPS traffic curl -x http://proxy.example.net:3128 https://api.example.com/ - 3.
在 STARTTLS 端口上使用 STARTTLS
对于邮件协议,curl 会在邮件提交端口和 IMAP 端口上通过 --ssl-reqd 升级连接,或者在 465 和 993 端口上通过 smtps:// 和 imaps:// 协议方案使用隐式 TLS。
bash # Port 587/25 (SMTP) and 143 (IMAP) start in plain text and upgrade with STARTTLS curl --ssl-reqd smtp://mail.example.com:587 -v # Implicit TLS lives on 465 (SMTPS) and 993 (IMAPS) curl smtps://mail.example.com:465 -v - 4.
服务器所有者:在监听器上启用 TLS
如果客户端应在这个端口上使用 https://,监听器就需要开启 TLS 并配置证书;否则就公布正确的端口。
text # nginx: the port that clients reach with https:// needs the ssl flag server { listen 443 ssl; ssl_certificate /etc/nginx/tls/fullchain.pem; ssl_certificate_key /etc/nginx/tls/privkey.pem; }
相关错误
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: WRONG_VERSION_NUMBER] wrong version numberPython ssl module (OpenSSL)http: server gave HTTP response to HTTPS clientGo net/httpjavax.net.ssl.SSLException: Unsupported or unrecognized SSL messageJava (JSSE)