Java/Kotlin
PR

【Java17】突然のSSLHandshakeExceptionを解決。原因はマイナーアップデートによる「暗号スイートの制限」だった

saratogax
記事内に商品プロモーションを含む場合があります

Java環境をアップデートした後、今まで正常に通信できていた外部APIとの接続で突然 SSLHandshakeException: Received fatal alert: handshake_failure が発生することはありませんか?

一見、接続先サーバーやネットワークの不具合に見えますが、実はJava17のマイナーアップデートによる「セキュリティの厳格化」が原因である場合があります。

今回は、原因の切り分けから解決に至るまでの実録をまとめました。

1. 事象:OSとJavaの更新後に通信不能に

開発環境や本番環境のベースイメージを更新した直後、特定の外部エンドポイントとの通信で以下のエラーがログに記録されました。

Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

接続先のサーバー側から「ハンドシェイク失敗」として通信を即座に切断されている状態です。直前まで疎通できていたことから、インフラ的な要因よりも「環境更新による通信プロトコルのミスマッチ」が疑われました。

2. 原因切り分けのためのデバッグ実行

まず、ネットワークの問題なのか、Java固有の問題なのかを切り分けるために以下の確認を行いました。

curlでの疎通確認(OSレベルの確認)

Podやコンテナ内に curl をインストールし、OSレベルでの疎通を確認します。

# curlでの詳細ログ確認
curl -v https://api.example.com

結果: 200 OK(成功) この結果から、ネットワーク経路や相手サーバー自体には問題がなく、「Javaという言語環境」特有の問題であることが確定しました。

keytoolによるSSLデバッグ

Javaの標準ツール keytool を使い、JVMがどのようにハンドシェイクを試みているか詳細ログを出力します。

keytool -printcert -sslserver api.example.com:443 -J-Djavax.net.debug=ssl,handshake

このログを確認したところ、相手サーバーが要求している暗号方式(Cipher Suite)に対し、Java側が適合するものを提示できていないことが分かりました。

3. 真犯人は「RSA鍵交換」の無効化

接続先のサーバー(特に金融系やレガシーな決済基盤)では、依然として以下の暗号スイートのみを許可しているケースがあります。

  • TLS_RSA_WITH_AES_256_GCM_SHA384
  • TLS_RSA_WITH_AES_256_CBC_SHA256 など

これらは static RSA(RSA 鍵転送)方式の暗号スイートで、名前が TLS_RSA_ で始まります。Java 17.0.18 で、この TLS_RSA_ 系がまとめてデフォルト無効化されました。具体的には java.securityjdk.tls.disabledAlgorithmsTLS_RSA_ が追加され、前方秘匿性(Forward Secrecy)を持たないことが理由とされています(RFC 9325 が static RSA を使うべきでないと勧告しています)。無効化されたスイートを使おうとすると SSLHandshakeException になります。

「RSA 鍵交換」と呼ばれることもありますが、正確には RSA 鍵転送(key transport)です。TLS 1.3 ではそもそも static RSA は廃止されており、影響を受けるのは TLS 1.2 以前で TLS_RSA_ 系スイートしか受け付けないサーバーに限られます。

4. 解決策:ベースイメージのバージョン固定

今回のケースでは、Javaのバージョンを 17.0.18 から 17.0.17 へ一段階戻すことで、即座に疎通が復旧しました。
(Docker イメージのバージョン固定をした)

恒久的な対応案

将来的にJavaを最新版に維持しつつ、レガシーな接続先と通信を続けるには、以下の対応が必要になります。

  1. Java のセキュリティ設定(java.security)の変更 jdk.tls.disabledAlgorithms の値から TLS_RSA_ を取り除くと、これらのスイートを再び使えます(前方秘匿性を捨てることになるので、あくまで暫定対応)。
  2. 接続先サーバーのモダナイズ依頼 接続先に対して、より安全な ECDHE(楕円曲線ディフィー・ヘルマン)方式のサポートを依頼する。

5. まとめ

Javaのマイナーアップデートは、単なるバグ修正だけでなく、今回のような「デフォルトセキュリティ設定の変更」が含まれることがあります。

  • curl は通るのに Java だけ失敗する
  • 特定の古い暗号方式(RSA等)しか受け付けない接続先がある

これらの条件が揃った際は、Javaのパッチバージョンによるセキュリティポリシーの差異をまず疑ってみてください。

参考(出典)

ABOUT ME
saratoga
saratoga
フリーランスエンジニア
仕事にも趣味にも IT を駆使するフリーランスエンジニア。技術的な TIPS や日々の生活の中で深堀りしてみたくなったことを備忘録として残していきます。
記事URLをコピーしました