错误信息
javax.net.ssl.SSLException: Unsupported or unrecognized SSL message
也可能输出为
- Unsupported or unrecognized SSL message
JDK 25 在客户端和收到纯 HTTP 的 JSSE 服务器上打印的文本相同(两种情况都已验证)。如果对端什么也不发送就关闭连接,Java 报告的则是“Remote host terminated the handshake”。
Java (JSSE) — the peer's reply is not a TLS record
含义
JSSE 等待的是 TLS 记录,收到的字节却无法按 TLS 记录解析,最常见的是纯 HTTP 服务器返回的 HTTP 响应文本。在客户端,这是对不使用 TLS 的端口使用了 https://;在服务器端(Tomcat 或 Netty 的 TLS 监听器),则是客户端向 TLS 端口发送了纯 HTTP。这里与证书无关。
原因
用 https:// 访问纯 HTTP 端口
常见位于终止 TLS 的代理后面的内部服务、actuator 或指标端口,以及本地开发服务器,通常使用纯 HTTP。
代理使用纯 HTTP,却被配置为 TLS
常见正向代理通常接受纯 HTTP,并通过 CONNECT 建立 HTTPS 隧道;如果把到代理本身的连接配置为 TLS,就会产生这个错误。
对 STARTTLS 端口使用隐式 TLS
偶见587/25 端口上的 SMTP(却在那里设置了 mail.smtp.ssl.enable=true)、用 ldaps:// 连接 389 端口上的 LDAP,或者要求在连接内升级的数据库。
服务器日志:客户端向 TLS 端口发送了纯 HTTP
偶见健康检查或用户访问 http://host:8443 时,TLS 连接器会为每个请求记录这条错误。
修复方法
- 1.
检查端口使用的协议
如果端口以纯 HTTP 应答,就使用 http://,或者改用真正的 TLS 端口。
bash curl -si http://api.example.com:8080/ | head -1 # an HTTP status line -> not TLS openssl s_client -connect api.example.com:8443 -brief </dev/null - 2.
邮件和目录客户端:让 TLS 模式与端口匹配
在邮件提交端口(587)上使用 STARTTLS,只在 465 端口上使用隐式 TLS(或在 636 端口上使用 ldaps://)。
text # Mail (Jakarta Mail): STARTTLS on 587, implicit TLS on 465 mail.smtp.port=587 mail.smtp.starttls.enable=true mail.smtp.starttls.required=true # (mail.smtp.ssl.enable=true belongs to port 465 only) - 3.
服务器所有者:分开 HTTP 和 HTTPS 端口
让客户端和健康检查使用 https://,或者开放一个重定向到 TLS 端口的纯 HTTP 连接器。
text # Spring Boot server logging this for incoming requests: plain HTTP sent to the TLS port. # Use https:// on server.port, or add a separate HTTP connector that redirects to HTTPS.