エラーメッセージ
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 を送信しています。この場合、証明書は関係ありません。
発生する理由
平文の HTTP のポートに https:// で接続している
よくあるTLS を終端するプロキシの背後にある内部サービス、Actuator やメトリクス用のポート、ローカルの開発用サーバーは、通常は平文の HTTP で通信します。
プロキシは平文の HTTP なのに TLS として設定されている
よくあるフォワードプロキシは通常、平文の HTTP を受け付け、HTTPS は CONNECT でトンネリングします。プロキシ自体への接続に TLS を設定すると、このエラーになります。
STARTTLS のポートに暗黙的 TLS で接続している
ときどき587/25 番ポートの SMTP(そこで mail.smtp.ssl.enable=true を指定している)、ldaps:// を使った 389 番ポートの LDAP、同じ接続内での TLS へのアップグレードを前提とするデータベースが該当します。
サーバーのログ:クライアントが 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 を使い、暗黙的 TLS は 465 番でだけ使ってください(ldaps:// なら 636 番)。
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.