Ich habe die SSL-Protokollierung in der Java 8 JVM auf einer Linux-Instanz aktiviert, die das Problem reproduziert. Die SSL-Protokollierung wird mit -Djavax.net.debug=ssl:handshake:verbose
aktiviert . Dabei kamen einige nützliche Informationen ans Licht.
Die Problemumgehung die wir in der Produktion verwenden und die sich für uns bewährt hat, besteht darin, diesen Parameter auf der JVM zu setzen:
-Djdk.tls.client.protocols=TLSv1
Wenn Sie weitere Einzelheiten wünschen, lesen Sie bitte weiter.
Auf einem Server, auf dem das Problem reproduziert werden kann (wieder nur in 5-10 % der Fälle), habe ich Folgendes beobachtet:
*** ClientHello, TLSv1.2
--- 8<-- SNIP -----
main, WRITE: TLSv1.2 Handshake, length = 195
main, READ: TLSv1.2 Handshake, length = 1130
*** ServerHello, TLSv1.2
--- 8<-- SNIP -----
%% Initialized: [Session-79, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256]
** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
--- 8<-- SNIP -----
Algorithm: [SHA1withRSA]
--- 8<-- SNIP -----
*** Diffie-Hellman ServerKeyExchange
--- 8<-- SNIP -----
*** ServerHelloDone
*** ClientKeyExchange, DH
--- 8<-- SNIP -----
main, WRITE: TLSv1.2 Handshake, length = 133
--- 8<-- SNIP -----
main, WRITE: TLSv1.2 Change Cipher Spec, length = 1
*** Finished
verify_data: { 108, 116, 29, 115, 13, 26, 154, 198, 17, 125, 114, 166 }
***
main, WRITE: TLSv1.2 Handshake, length = 40
main, called close()
main, called closeInternal(true)
main, SEND TLSv1.2 ALERT: warning, description = close_notify
main, WRITE: TLSv1.2 Alert, length = 26
main, called closeSocket(true)
main, waiting for close_notify or alert: state 5
main, received EOFException: ignored
main, called closeInternal(false)
main, close invoked again; state = 5
main, handling exception: java.io.IOException: SQL Server returned an incomplete response. The connection has been closed. ClientConnectionId:12a722b3-d61d-4ce4-8319-af049a0a4415
Beachten Sie, dass TLSv1.2 wird vom Datenbankserver ausgewählt und in diesem Austausch verwendet. Ich habe beobachtet, dass, wenn Verbindungen vom problematischen Linux-Dienst fehlschlagen, TLSv1.2 IMMER die ausgewählte Ebene ist. Verbindungen schlagen jedoch nicht IMMER fehl, wenn TLSv1.2 verwendet wird. Sie versagen nur in 5–10 % der Fälle.
Hier ist jetzt ein Austausch von einem Server, der das Problem NICHT hat. Alles andere ist gleich. Das heißt, eine Verbindung mit derselben Datenbank, derselben Version der JVM (Java 1.8.0_60), demselben JDBC-Treiber usw. Beachten Sie, dass hier TLSv1 wird vom Datenbankserver anstelle von TLSv1.2 wie im Fall des fehlerhaften Servers ausgewählt.
*** ClientHello, TLSv1.2
--- 8<-- SNIP -----
main, WRITE: TLSv1.2 Handshake, length = 207
main, READ: TLSv1 Handshake, length = 604
*** ServerHello, TLSv1
--- 8<-- SNIP -----
Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA
--- 8<-- SNIP -----
%% Initialized: [Session-79, TLS_RSA_WITH_AES_128_CBC_SHA]
** TLS_RSA_WITH_AES_128_CBC_SHA
--- 8<-- SNIP -----
Algorithm: [SHA1withRSA]
--- 8<-- SNIP -----
***
*** ServerHelloDone
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
--- 8<-- SNIP -----
main, WRITE: TLSv1 Handshake, length = 134
main, WRITE: TLSv1 Change Cipher Spec, length = 1
*** Finished
verify_data: { 26, 155, 166, 89, 229, 193, 126, 39, 103, 206, 126, 21 }
***
main, WRITE: TLSv1 Handshake, length = 48
main, READ: TLSv1 Change Cipher Spec, length = 1
main, READ: TLSv1 Handshake, length = 48
*** Finished
Wenn also TLSv1 zwischen der Linux-JVM und dem SQL Server ausgehandelt wird, sind Verbindungen IMMER erfolgreich. Wenn TLSv1.2 ausgehandelt wird, kommt es zu sporadischen Verbindungsabbrüchen.
(Hinweis:Java 7 (1.7.0_51) handelt immer TLSv1 aus, weshalb das Problem bei uns mit einer Java 7 JVM nie aufgetreten ist.)
Die offenen Fragen, die wir noch haben, sind:
- WARUM ist, dass die gleiche Java 8 JVM, die von zwei verschiedenen Linux-Servern ausgeführt wird, immer TLSv1 aushandelt, aber wenn eine Verbindung von einem anderen Linux-Server hergestellt wird, verhandelt sie immer TLSv1.2.
- Und warum sind über TLSv1.2 ausgehandelte Verbindungen meistens, aber nicht immer, auf diesem Server erfolgreich?
Aktualisierung vom 10.06.2017: Dieser Beitrag von Microsoft beschreibt das Problem und die vorgeschlagene Lösung.
Ressourcen:
http://www.infoworld.com/article/2849292/operating-systems/more-patch-problems-reported-with-the-ms14-066-kb-2992611-winshock-mess.html
http://www.infoworld.com/article/2849292/operating-systems/more-patch-problems-reported-with-the-ms14-066-kb-2992611-winshock-mess.html
http://blogs.msdn.com/b/jdbcteam/archive/2008/09/09/the-driver-could-not-making-a-secure-connection-to-sql-server-by-using-secure- sockets-layer-ssl-verschlüsselung.aspx
Java 8 , JCE Unlimited Strength Policy und SSL-Handshake über TLS
http://blogs.msdn.com/b/saponsqlserver/archive/2013/05/10/analyzing-jdbc-connection-issues.aspx
https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#descPhase2
https://blogs.oracle.com/java-platform-group/entry/java_8_will_use_tls
Dies scheint in Version 4.2 des MS SQL JDBC-Treibers behoben worden zu sein. Ich habe ein Programm erstellt, bei dem ich mich 1000 Mal mit dem Server verbunden habe und zwischen jedem Versuch 100 ms pausiert habe. Mit der Version 4.1 konnte ich das Problem jedes Mal reproduzieren, obwohl es nur sporadisch auftrat. Mit Version 4.2 konnte ich das Problem nicht reproduzieren.
Prüfen Sie vor dem Upgrade des SQL JDBC-Treibers zunächst die Kompatibilität:
- Sqljdbc.jar erfordert eine JRE von 5 und unterstützt die JDBC 3.0 API
- Sqljdbc4.jar erfordert JRE 6 und unterstützt die JDBC 4.0 API
- Sqljdbc41.jar erfordert JRE 7 und unterstützt die JDBC 4.1 API
- Sqljdbc42.jar erfordert JRE 8 und unterstützt die JDBC 4.2 API
Quelle:https://www.microsoft.com/en-us/download/details.aspx?id=11774