it-swarm.com.de

SQL Server-JDBC-Fehler auf Java 8: Der Treiber konnte mit der SSL-Verschlüsselung (Secure Sockets Layer) keine sichere Verbindung zu SQL Server herstellen

Beim Herstellen einer Verbindung zu einer SQL Server-Datenbank mit der Version des Microsoft JDBC-Treibers wird die folgende Fehlermeldung angezeigt:

com.Microsoft.sqlserver.jdbc.SQLServerException: Der Treiber konnte mithilfe der SSL-Verschlüsselung (Secure Sockets Layer) keine sichere Verbindung zu SQL Server herstellen. Fehler: "SQL Server hat eine unvollständige Antwort zurückgegeben. Die Verbindung wurde geschlossen. ClientConnectionId: 98d0b6f4-f3ca-4683-939e-7c0a0fca5931".

Wir haben kürzlich unsere Anwendungen von Java 6 und Java 7 auf Java 8 aktualisiert. Auf allen Systemen, auf denen Java ausgeführt wird, wird SUSE Linux Enterprise Server 11 (x86_64), VERSION = 11, PATCHLEVEL = 3 ausgeführt.

Hier sind die Fakten, die ich mit einem Java-Programm zusammengetragen habe, das einfach 1.000 Datenbankverbindungen öffnet und schließt.

  • Verbindungen werden mit diesem Fehler in etwa 5-10% der Zeit unterbrochen. Der Fehler tritt NICHT bei jeder Verbindung auf.
  • Das Problem tritt NUR bei Java 8 auf. Ich habe dasselbe Programm auf Java 7 ausgeführt und das Problem ist nicht reproduzierbar. Dies entspricht unserer Erfahrung in der Produktion vor dem Upgrade. Wir hatten keine Probleme mit Java 7 in der Produktion.
  • Das Problem tritt NICHT auf allen Linux-Servern auf, auf denen Java 8 ausgeführt wird. Es tritt nur bei einigen von ihnen auf. Dies ist verwirrend für mich, aber wenn ich dasselbe Testprogramm auf der gleichen Version der Linux-JVM (1.8.0_60, 64-Bit) auf verschiedenen Linux-Instanzen ausführen, tritt das Problem nicht bei einer der Linux-Instanzen auf, sondern das Problem tritt bei anderen auf. Die Linux-Instanzen führen dieselbe Version von SUSE aus und befinden sich auf demselben Patch-Level.
  • Das Problem tritt auf, wenn eine Verbindung zu beiden Servern/Datenbanken von SQL Server 2008 und SQL Server 2014 hergestellt wird.
  • Das Problem tritt unabhängig davon auf, ob ich die 4.0-Version des SQL Server-JDBC-Treibers oder die neuere 4.1-Version des Treibers verwende.

Was meine Beobachtungen im Vergleich zu anderen im Web einzigartig macht, ist die Tatsache, dass das Problem NUR auf Java 8 auftritt, ich jedoch nicht auf einem der scheinbar identischen Linux-Server auftreten kann, auf dem dieselbe Java 8-JVM ausgeführt wird. Andere Leute haben dieses Problem auch in früheren Java-Versionen gesehen, aber das ist nicht unsere Erfahrung.

Alle Eingaben, Vorschläge oder Beobachtungen, die Sie haben, werden geschätzt.

22
2Aguy

Ich habe die SSL-Protokollierung in der Java 8-JVM in einer Linux-Instanz aktiviert, die das Problem reproduziert. Die SSL-Protokollierung wird mit -Djavax.net.debug=ssl:handshake:verbose aktiviert. Dies ergab einige nützliche Informationen. 

Der workaround, den wir in der Produktion verwenden und sich für uns bewährt haben, besteht darin, diesen Parameter in der JVM einzustellen:

 -Djdk.tls.client.protocols=TLSv1

Wenn Sie mehr Details wünschen, lesen Sie bitte weiter.

Auf einem Server, auf dem das Problem reproduziert werden kann (wiederum nur 5-10% der Zeit), habe ich Folgendes festgestellt:

*** 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 vom Datenbankserver ausgewählt und in diesem Austausch verwendet wird. Ich habe festgestellt, dass TLSv1.2 IMMER die Ebene ist, die ausgewählt wurde, wenn Verbindungen aus dem problematischen Linux-Dienst ausfallen. Verbindungen schlagen jedoch IMMER nicht fehl, wenn TLSv1.2 verwendet wird. Sie versagen nur 5-10% der Zeit.

Hier nun ein Austausch von einem Server, der das Problem NICHT hat. Alles andere ist gleich. Das heißt, es wird eine Verbindung zu derselben Datenbank, derselben Version der JVM (Java 1.8.0_60), demselben JDBC-Treiber usw. hergestellt. Beachten Sie, dass hier TLSv1 vom Datenbankserver anstelle von TLSv1.2 ausgewählt wird fehlerhafter Serverfall.

*** 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 die Verbindungen IMMER erfolgreich. Wenn TLSv1.2 ausgehandelt wird, kommt es zu sporadischen Verbindungsfehlern. 

(Hinweis: Java 7 (1.7.0_51) handelt immer TLSv1 aus, weshalb das Problem bei einer Java 7-JVM für uns nie aufgetreten ist.)

Die offenen Fragen, die wir noch haben, sind: 

  1. WARUM ist es so, dass dieselbe Java 8-JVM, die von zwei verschiedenen Linux-Servern ausgeführt wird, TLSv1 immer aushandelt. Wenn Sie jedoch eine Verbindung mit einem anderen Linux-Server herstellen, handelt TLSv1.2 immer aus. 
  2. Und warum sind TLSv1.2-Verbindungen meistens erfolgreich, aber nicht die ganze Zeit auf diesem Server?

Update 6/10/2017:Dieses Posting von Microsoft beschreibt das Problem und seine vorgeschlagene Lösung.

Ressourcen:

http://www.infoworld.com/article/2849292/operating-systems/more-patch-problems-reported-mit-the-ms14-066-kb-2992611-winshock-mess.html

http://www.infoworld.com/article/2849292/operating-systems/more-patch-problems-reported-mit-the-ms14-066-kb-2992611-winshock-mess.html

http://blogs.msdn.com/b/jdbcteam/archive/2008/09/09/the-driver-could-not-establish-a-secure-connection-to-sql-server-by-using- Secure-Sockets-Layer-SSL-Verschlüsselung.aspx

Java 8, JCE Unlimited Strength Policy und SSL Handshake over 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

21
2Aguy

Dies scheint in Version 4.2 des MS SQL JDBC-Treibers behoben worden zu sein. Ich habe ein Programm erstellt, mit dem ich mich 1000 Mal mit dem Server verbunden habe und zwischen jedem Versuch 100 ms angehalten habe. Mit Version 4.1 konnte ich das Problem jedes Mal reproduzieren, obwohl es nur sporadisch geschah. Mit Version 4.2 konnte ich das Problem nicht reproduzieren.

5
Tore Refsnes

Überprüfen Sie vor dem Upgrade des SQL JDBC-Treibers zuerst die Kompatibilität:

  • Sqljdbc.jar erfordert eine JRE von 5 und unterstützt die JDBC 3.0-API 
  • Sqljdbc4.jar erfordert eine JRE von 6 und unterstützt die JDBC 4.0-API 
  • Sqljdbc41.jar erfordert eine JRE von 7 und unterstützt die JDBC 4.1-API 
  • Sqljdbc42.jar erfordert eine JRE von 8 und unterstützt die JDBC 4.2-API 

Quelle: https://www.Microsoft.com/de-de/download/details.aspx?id=11774

4
bbhagat

In meinem Fall hatte ich einen SQL-Server, der den 3DES_EDE_CBC-Algorithmus verwendete. Dies ist in jdk 1.8 standardmäßig deaktiviert

/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/security/Java.security

Und den Algorithmus eliminieren aus:

jdk.tls.disabledAlgorithms = SSLv3, RC4, DES, MD5withRSA, DH-Schlüsselgröße <1024,\EC-Schlüsselgröße <224, 3DES_EDE_CBC, anon, NULL

Hat für mich gearbeitet.

2
cabaji99

Ich habe dieses Problem auch unter Windows Server 2012 R2 unter Verwendung des JDBC-Treibers 4.0 & 4.1 mit Java 7 festgestellt. In diesem Microsoft-Artikel sind DHE-Ciphersuites verantwortlich gemacht. Es wird empfohlen, sie zu deaktivieren oder ihre Priorität zu reduzieren, wenn Sie kein Upgrade durchführen können JDBC-Treiber 4.2

1
coolhand

Microsoft hat kürzlich einen Treiber für den Treiber geöffnet. Auf GitHub kann man die Aktivität " mssql-jdbc " sehen. Ich vermute, die neueste Vorschau ist 6.1.5. 

Sie können auch alle Vorschauversionen auf maven finden. Unterstützung für JDK7 und JDK 8.

1
Nikhil

Ihre URL sollte wie unten angegeben sein und sqljdbc42.jar hinzufügen. Dies wird Ihr Problem beheben

url = "jdbc:sqlserver://" +serverName + ":1433;DatabaseName=" + dbName + ";encrypt=true;trustServerCertificate=true;
0
Sunil Kumar