Fehlermeldung
javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
Auch ausgegeben als
- Remote host terminated the handshake
JDK 21 und 25 geben „Remote host terminated the handshake“ aus. In Logs von Java 8 erscheint dieselbe Situation meist als „Remote host closed connection during handshake“, verursacht durch „SSL peer shut down incorrectly“.
Java (JSSE) — the TCP connection closed during the handshake without a TLS alert
Was der Fehler bedeutet
Die Gegenseite (oder etwas dazwischen) hat die TCP-Verbindung mitten im TLS-Handshake der JVM geschlossen, ohne einen TLS-Alert zu senden. Java kann den Grund nicht kennen; es sieht nur, dass die Verbindung endet. Typischerweise verwirft eine Firewall, ein Proxy oder ein Load Balancer den Handshake, oder der Server lehnt das ClientHello stillschweigend ab.
Warum der Fehler auftritt
Ein Proxy oder eine Firewall auf dem Weg
häufigNetze, die einen HTTPS-Proxy vorschreiben, Firewalls mit Deep Packet Inspection, die nach SNI oder JA3-/JA4-Fingerprint blockieren, und VPNs beenden blockierte Verbindungen oft stillschweigend.
Der Server schließt die Verbindung bei Handshakes, die er ablehnt
häufigManche Server und Load Balancer schließen die Verbindung, statt mit einem Alert zu antworten, wenn Protokollversion, Cipher-Liste oder SNI für sie nicht akzeptabel sind.
SNI fehlt
gelegentlichEine Verbindung über die IP-Adresse oder mit jsse.enableSNIExtension=false sendet keinen Servernamen; Edge-Server von CDNs verwerfen solche Handshakes häufig.
Verbindungslimits und Rate Limiting
gelegentlichServer am Verbindungslimit oder Rate Limiter bei Lastspitzen setzen neue Verbindungen zurück; der Fehler tritt dann nur sporadisch auf.
So behebst du den Fehler
- 1.
Handshake protokollieren und mit openssl vergleichen
javax.net.debug zeigt, wie weit der Handshake gekommen ist; wird auch die Verbindung von openssl s_client auf demselben Host gekappt, liegt die Ursache im Netz oder beim Server, nicht in der JVM.
bash java -Djavax.net.debug=ssl:handshake -jar app.jar 2>&1 | grep -E 'ClientHello|server_name|EOF|terminated' # Same handshake without Java: is it the network or the JVM? openssl s_client -connect api.example.com:443 -servername api.example.com -brief </dev/null - 2.
Proxy des Netzes verwenden
Java verwendet standardmäßig weder die Proxy-Einstellungen des Betriebssystems noch die des Browsers; setze https.proxyHost/https.proxyPort (oder -Djava.net.useSystemProxies=true) und nimm interne Hosts mit http.nonProxyHosts aus.
bash # Corporate networks: route HTTPS through the proxy the browser uses java -Dhttps.proxyHost=proxy.example.net -Dhttps.proxyPort=3128 \ -Dhttp.nonProxyHosts="localhost|*.internal.example.com" -jar app.jar - 3.
SNI senden
Verwende den Hostnamen in der URL und lass die SNI-Erweiterung aktiviert.
text Connect with the host name (not an IP address) so JSSE sends SNI, and do not set -Djsse.enableSNIExtension=false: front ends that need SNI close such connections.