[英]SQL Server JDBC Error on Java 8: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption
I am getting the following error when connecting to a SQL Server database using version the Microsoft JDBC Driver:使用 Microsoft JDBC 驱动程序版本连接到 SQL 服务器数据库时出现以下错误:
com.microsoft.sqlserver.jdbc.SQLServerException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. com.microsoft.sqlserver.jdbc.SQLServerException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "SQL Server returned an incomplete response. The connection has been closed. ClientConnectionId:98d0b6f4-f3ca-4683-939e-7c0a0fca5931".错误:“SQL Server 返回不完整的响应。连接已关闭。ClientConnectionId:98d0b6f4-f3ca-4683-939e-7c0a0fca5931”。
We recently upgraded our applications from Java 6 & Java 7 to Java 8. All systems running Java are running SUSE Linux Enterprise Server 11 (x86_64), VERSION = 11, PATCHLEVEL = 3. We recently upgraded our applications from Java 6 & Java 7 to Java 8. All systems running Java are running SUSE Linux Enterprise Server 11 (x86_64), VERSION = 11, PATCHLEVEL = 3.
Here are the facts I have collected with a Java program that I wrote which simply sequentially opens and closes 1,000 database connections.以下是我使用我编写的 Java 程序收集的事实,该程序只是按顺序打开和关闭 1,000 个数据库连接。
The thing that makes my observations unique on this compared to others on the web is that although the problem happens ONLY on Java 8, I cannot get the problem to occur on one of the seemingly identical Linux servers that is running the same Java 8 JVM. The thing that makes my observations unique on this compared to others on the web is that although the problem happens ONLY on Java 8, I cannot get the problem to occur on one of the seemingly identical Linux servers that is running the same Java 8 JVM. Other folks have seen this problem on earlier versions of Java as well, but that has not been our experience.其他人在早期版本的 Java 上也看到了这个问题,但这不是我们的经验。
Any input, suggestions, or observations you may have are appreciated.感谢您提供的任何意见、建议或意见。
Your url should be like below and add sql sqljdbc42.jar.您的 url 应该如下所示并添加 sql sqljdbc42.jar。 This will resolve your issue这将解决您的问题
url = "jdbc:sqlserver://" +serverName + ":1433;DatabaseName=" + dbName + ";encrypt=true;trustServerCertificate=true;
I turned on SSL logging in the Java 8 JVM on a Linux instance which reproduces the problem.我在重现问题的 Linux 实例上的 Java 8 JVM 中打开了 SSL 日志记录。 SSL logging is turned on using -Djavax.net.debug=ssl:handshake:verbose
.使用-Djavax.net.debug=ssl:handshake:verbose
打开 SSL 日志记录。 This revealed some useful information.这揭示了一些有用的信息。
The workaround that we are using in production and has proven to work for us is to set this parameter on the JVM:我们在生产中使用并已证明对我们有用的解决方法是在 JVM 上设置此参数:
-Djdk.tls.client.protocols=TLSv1
If you want more details, please read on.如果您想了解更多详情,请继续阅读。
On a server where the problem can be reproduced (again, only 5-10% of the time), I observed the following:在可以重现问题的服务器上(同样,只有 5-10% 的时间),我观察到以下情况:
*** 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
Notice that TLSv1.2 is selected by the database server and used in this exchange.请注意,数据库服务器选择了TLSv1.2并在此交换中使用。 I've observed that, when connections fail from the problematic linux service, TLSv1.2 is ALWAYS the level which was selected.我观察到,当有问题的 linux 服务连接失败时,TLSv1.2 始终是选择的级别。 However, connections do not ALWAYS fail when TLSv1.2 is used.但是,使用 TLSv1.2 时,连接并不总是失败。 They only fail 5-10% of the time.他们只有 5-10% 的时间失败。
Now here is an exchange from a server that does NOT have the problem.现在这是来自没有问题的服务器的交换。 Everything else is equal.其他一切都是平等的。 Ie, connecting to the same database, same version of the JVM (Java 1.8.0_60), same JDBC driver, etc. Notice that, here, TLSv1 is selected by the database server instead of TLSv1.2 as in the faulty server's case.即,连接到相同的数据库、相同版本的 JVM(Java 1.8.0_60)、相同的 JDBC 驱动程序等。请注意,这里的数据库服务器选择的是TLSv1 ,而不是故障服务器情况下的 TLSv1.2。
*** 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
So, when TLSv1 is negotiated between the Linux JVM and the SQL Server, connections are ALWAYS successful.因此,当 Linux JVM 和 SQL Server 之间协商 TLSv1 时,连接总是成功的。 When TLSv1.2 is negotiated, we get sporadic connection failures.协商 TLSv1.2 时,我们会遇到零星的连接失败。
(Note: Java 7 (1.7.0_51) always negotiates TLSv1, which is why the problem never occurred for us with a Java 7 JVM.) (注意:Java 7 (1.7.0_51) 总是协商 TLSv1,这就是为什么我们在使用 Java 7 JVM 时从未出现过问题。)
The open questions we still have are:我们仍有待解决的问题是:
Update 6/10/2017: This posting from Microsoft describes the problem and their proposed solution. 2017 年 6 月 10 日更新: Microsoft 发布的此帖子描述了该问题及其建议的解决方案。
Resources:资源:
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://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-establish-a-secure-connection-to-sql-server-by-using-secure-sockets-layer-ssl-encryption.aspx 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-encryption.aspx
Java 8 , JCE Unlimited Strength Policy and SSL Handshake over TLS Java 8、JCE 无限强度策略和基于 TLS 的 SSL 握手
http://blogs.msdn.com/b/saponsqlserver/archive/2013/05/10/analyzing-jdbc-connection-issues.aspx 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://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 https://blogs.oracle.com/java-platform-group/entry/java_8_will_use_tls
In case someone arrives here looking for a solution to connect to a database from PhpStorm, just add the following after the port in the URL:如果有人来到这里寻找从 PhpStorm 连接到数据库的解决方案,只需在 URL 中的端口后添加以下内容:
;encrypt=true;trustServerCertificate=true;
I got the solution from this comment: SQL Server JDBC Error on Java 8: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption我从这条评论中得到了解决方案: Java 8 上的 SQL Server JDBC 错误:驱动程序无法通过使用安全套接字层 (SSL) 加密建立与 SQL Server 的安全连接
Thank you so much!太感谢了! Can confirm it's working on PhpStorm 2022.1.1.可以确认它在 PhpStorm 2022.1.1 上运行。
This appears to have been fixed in version 4.2 of the MS SQL JDBC driver.这似乎已在 MS SQL JDBC 驱动程序的 4.2 版中得到修复。 I created a program where I connected to the server 1000 times, pausing 100ms between each attempt.我创建了一个程序,我连接到服务器 1000 次,每次尝试之间暂停 100 毫秒。 With version 4.1 I was able to reproduce the problem every time, although it happened only sporadically.使用 4.1 版,我每次都能重现该问题,尽管它只是偶尔发生。 With version 4.2 I was unable to reproduce the problem.使用 4.2 版我无法重现该问题。
Before you upgrade SQL JDBC Driver, check the compatibility first:在升级 SQL JDBC Driver 之前,请先检查兼容性:
Source: https://www.microsoft.com/en-us/download/details.aspx?id=11774来源: https ://www.microsoft.com/en-us/download/details.aspx?id=11774
Issue got resolved for me when I changed the sqljdbc-4.2.0 jar with mssql-jdbc-8.4.1 jar当我用 mssql-jdbc-8.4.1 jar 更改 sqljdbc-4.2.0 jar 时,问题得到了解决
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>8.4.1.jre8</version>
</dependency>
In my case i had a sql server using the 3DES_EDE_CBC algorithm, this is disabled by default on jdk 1.8 , so checking the在我的情况下,我有一个使用 3DES_EDE_CBC 算法的 sql 服务器,这在 jdk 1.8 默认情况下被禁用,所以检查
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/security/java.security /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/security/java.security
And eliminating the algorithm from:并从以下方面消除算法:
jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \ EC keySize < 224, 3DES_EDE_CBC, anon, NULL jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \ EC keySize < 224, 3DES_EDE_CBC, anon, NULL
Worked for me.为我工作。
Like @2Aguy wrote, you can change the JVM parameter.就像@2Aguy 写的那样,您可以更改 JVM 参数。 In my case I couldn't change it, and used the connection string " sslProtocol " parameter, lowering the connection to TLSV1.在我的情况下,我无法更改它,并使用连接字符串“ sslProtocol ”参数,降低与 TLSV1 的连接。
Connection String: jdbc:sqlserver://<HOST>:<PORT>;encrypt=true;trustServerCertificate=true;sslProtocol=TLSv1;database=<DB NAME>连接字符串:jdbc:sqlserver://<HOST>:<PORT>;encrypt=true;trustServerCertificate=true;sslProtocol=TLSv1;database=<DB NAME>
使用 openjdk 11 可以将以下属性添加到连接 URL 以强制使用 SSL
;integratedSecurity=false;encrypt=false;trustServerCertificate=true;
Microsoft Recently open sourced their driver.微软最近开源了他们的驱动程序。 One can see mssql-jdbc driver activity on GitHub.可以在 GitHub 上查看mssql-jdbc驱动程序活动。 I guess latest preview version is 6.1.5.我猜最新的预览版是 6.1.5。
Also you can find all preview versions on maven too.您也可以在 Maven 上找到所有预览版本。 Supporting both JDK7 & JDK 8.同时支持 JDK7 和 JDK 8。
我在 Windows Server 2012 R2 上也遇到了这个问题,使用 JDBC 驱动程序 4.0 和 4.1 和 Java 7。这篇Microsoft 文章将责任归咎于 DHE 密码套件,并建议在无法升级到 JDBC 驱动程序 4.2 时禁用它们或降低它们的优先级
In my case, the issue was because the app was set to use spring-boot-ext-security-starter-credhub-credential and there were some issues with that setup.就我而言,问题是因为该应用程序设置为使用 spring-boot-ext-security-starter-credhub-credential 并且该设置存在一些问题。
So I removed credhub from the manifest file and pom and fetched credentials in a different way;所以我从清单文件和 pom 中删除了 credhub 并以不同的方式获取凭据; then the error was gone.然后错误消失了。
If the server name in the connection string does not match the server name in the SQL Server SSL certificate, the following error will be issued: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption.如果连接字符串中的服务器名称与 SQL Server SSL 证书中的服务器名称不匹配,则会发出以下错误:驱动程序无法使用安全套接字层 (SSL) 加密建立与 SQL Server 的安全连接。 Error: "java.security.cert.CertificateException: Failed to validate the server name in a certificate during Secure Sockets Layer (SSL) initialization."错误:“java.security.cert.CertificateException:在安全套接字层 (SSL) 初始化期间无法验证证书中的服务器名称。”
This helped me resolve the issue.这帮助我解决了这个问题。 Was using the localhost in servername, finally changing in jdbc connection string to the same name as the CN was able to connect.在 servername 中使用 localhost,最后将 jdbc 连接字符串更改为与 CN 能够连接的名称相同的名称。
Refer: https://wiki.deepnetsecurity.com/pages/viewpage.action?pageId=1410867 for more info请参阅: https ://wiki.deepnetsecurity.com/pages/viewpage.action?pageId=1410867 了解更多信息
Thanks to @Sunil Kumar and @Joce.感谢@Sunil Kumar 和@Joce。 I used the jar and below syntax:我使用了 jar 和以下语法:
String myDriver = "com.microsoft.jdbc.sqlserver.SQLServerDriver"; String myDriver = "com.microsoft.jdbc.sqlserver.SQLServerDriver";
String myURL = "jdbc:sqlserver://DB_ipaddress\DB_instance;databaseName=DB_name;user=myusername; password=mypass;encrypt=true;trustServerCertificate=true;"; String myURL = "jdbc:sqlserver://DB_ipaddress\DB_instance;databaseName=DB_name;user=myusername;password=mypass;encrypt=true;trustServerCertificate=true;"; / ==> here the semicolon will be twice like shown / / ==>这里的分号将像显示的那样加倍/
Connection con = DriverManager.getConnection(myURL); Connection con = DriverManager.getConnection(myURL);
I had this issue recently after doing a yum update in a client's server running RedHat 7. Since the above thread did not help me resolve my issue, I am posting this answer.我最近在运行 RedHat 7 的客户端服务器上进行了 yum 更新后遇到了这个问题。由于上述线程没有帮助我解决我的问题,我发布了这个答案。
Issue:- Yum update in RedHat automatically reinstalls OpenJDK , my applications use oracle JDK.问题:- RedHat 中的 Yum 更新自动重新安装 OpenJDK,我的应用程序使用 oracle JDK。 Verifying Default JDK:验证默认 JDK:
java version Switch the default version: java version 切换默认版本:
update-alternatives --config java更新替代品--config java
There are 2 programs which provide 'java'.有 2 个程序提供“java”。
Enter to keep the current selection[+], or type selection number: Enter 以保留当前选择[+],或输入选择编号:
Enter the number alongside the appropriate version you want to us and hit enter.在您希望我们提供的相应版本旁边输入数字,然后按 Enter。
I have fixed the issue on my local enviroment, it mainly contains two steps below.我已经在我的本地环境中解决了这个问题,它主要包含以下两个步骤。
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<version>1.3.1</version>
</dependency>
2.Replace the Driver Class Name additionally: 2.另外替换驱动程序类名称:
ru.yandex.clickhouse.ClickHouseDriver
3.Modify the JDBC URL like this: 3.修改JDBC URL,如下所示:
jdbc:jtds:sqlserver://xxxx:1433;databaseName=xxx
I have also faced same issue while creating connection to the database with below connection string.在使用以下连接字符串创建与数据库的连接时,我也遇到了同样的问题。
DriverManager.getConnection("jdbc:sqlserver://" + host + ":" + port + ";databaseName=" + dbName + ";user=" + userName + ";password=" + password);
After updating connection string as below, it worked.如下更新连接字符串后,它起作用了。
Connection con = DriverManager.getConnection("jdbc:sqlserver://" + host + ":" + port + ";databaseName=" + dbName + ";encrypt=true;trustServerCertificate=true;user=" + userName + ";password=" + password);
here i have added encrypt=true;trustServerCertificate=true
after the database name.在这里,我在数据库名称后添加了encrypt=true;trustServerCertificate=true
。
spring.datasource.url=jdbc:sqlserver://YourServerName:1433;database=<YourDatabaseName>;encrypt=true;trustServerCertificate=true;
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.show-sql=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.jpa.hibernate.ddl-auto = create-drop
For me I add to add Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
对我来说,我添加添加Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
between the two lines两条线之间
DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());
Connection con = DriverManager.getConnection(connectionUrl);
So the final code for the connection would be:所以连接的最终代码是:
DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection con = DriverManager.getConnection(connectionUrl);
Add;encrypt=true;trustServerCertificate=true into connection.url Example jdbc:sqlserver://localhost\SQLEXPRESS:1433;databaseName=testdb;encrypt=true;trustServerCertificate=true And check Compatible jre in pom file with version mssql-jdbc of maven.将;encrypt=true;trustServerCertificate=true 添加到 connection.url 示例 jdbc:sqlserver://localhost\SQLEXPRESS:1433;databaseName=testdb;encrypt=true;trustServerCertificate=true 并检查与 pom 中的 ms-jj 文件兼容的 jre maven。 Like this enter image description here像这样在此处输入图像描述
Add ;encrypt=true;trustServerCertificate=true
into connection.url.将;encrypt=true;trustServerCertificate=true
添加到 connection.url 中。 Example例子
jdbc:sqlserver://localhost\SQLEXPRESS:1433;databaseName=testdb;encrypt=true;trustServerCertificate=true jdbc:sqlserver://localhost\SQLEXPRESS:1433;databaseName=testdb;encrypt=true;trustServerCertificate=true
And check Compatible compiler version java in pom file with version jre of mssql-jdbc of maven.并在 pom 文件中使用 maven 的 mssql-jdbc 的 jre 版本检查 Compatible compiler version java。 Like this像这样
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
And和
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>11.2.1.jre8</version>
</dependency>
compiler 1.8 and jre8编译器 1.8 和 jre8
JUST USE ENCRYPT PROTOCOL ET TRUST SERVER CERTIFICAT encrypt=true;trustServerCertificate=true只需使用加密协议 ET 信任服务器证书 encrypt=true;trustServerCertificate=true
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.