Java 8 上的 SQL Server JDBC 错误:驱动程序无法使用安全套接字层 (SSL) 加密与 SQL Server 建立安全连接
- 2024-10-14 08:39:00
- admin 原创
- 77
问题描述:
使用 Microsoft JDBC Driver 版本连接到 SQL Server 数据库时出现以下错误:
com.microsoft.sqlserver.jdbc.SQLServerException:驱动程序无法使用安全套接字层 (SSL) 加密与 SQL Server 建立安全连接。错误:“SQL Server 返回了不完整的响应。连接已关闭。ClientConnectionId:98d0b6f4-f3ca-4683-939e-7c0a0fca5931”。
我们最近将我们的应用程序从 Java 6 和 Java 7 升级到了 Java 8。所有运行 Java 的系统都运行 SUSE Linux Enterprise Server 11 (x86_64),版本 = 11,补丁级别 = 3。
以下是我使用自己编写的 Java 程序收集的事实,该程序只是按顺序打开和关闭 1,000 个数据库连接。
出现此错误时,连接断开的概率约为 5%-10%。此错误并非在每个连接上都发生。
该问题仅发生在 Java 8 上。我在 Java 7 上运行了相同的程序,问题未重现。这与升级前我们在生产中的经验一致。在生产中,我们在 Java 7 下运行时没有遇到任何问题。
该问题并非发生在我们所有运行 Java 8 的 Linux 服务器上,它只发生在其中一部分服务器上。这让我感到困惑,但是当我在不同的 Linux 实例上在同一版本的 Linux JVM(1.8.0_60,64 位)上运行相同的测试程序时,该问题不会发生在其中一个 Linux 实例上,但会发生在其他实例上。Linux 实例运行的是相同版本的 SUSE,并且它们处于相同的补丁级别。
连接到 SQL Server 2008 和 SQL Server 2014 服务器/数据库时出现问题。
无论我使用的是 4.0 版 SQL Server JDBC 驱动程序还是较新的 4.1 版驱动程序,都会出现此问题。
与网上其他人的观察相比,我的观察结果与众不同之处在于,尽管该问题仅发生在 Java 8 上,但我无法在运行相同 Java 8 JVM 的看似相同的 Linux 服务器上看到该问题。其他人也在早期版本的 Java 上看到过这个问题,但我们没有遇到过这种情况。
欢迎您提供任何意见、建议或意见。
解决方案 1:
您的 URL 应如下所示,并添加 sql sqljdbc42.jar。这将解决您的问题
url = "jdbc:sqlserver://" +serverName + ":1433;DatabaseName=" + dbName + ";encrypt=true;trustServerCertificate=true;
解决方案 2:
我在 Linux 实例上的 Java 8 JVM 中打开了 SSL 日志记录,该实例重现了该问题。使用 打开了 SSL 日志记录 -Djavax.net.debug=ssl:handshake:verbose
。这揭示了一些有用的信息。
我们在生产中使用的、已被证明有效的解决方法是在 JVM 上设置此参数:
-Djdk.tls.client.protocols=TLSv1
如果您想了解更多详细信息,请继续阅读。
在可以重现该问题的服务器上(同样,只有 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
请注意,数据库服务器选择了TLSv1.2并用于此交换。我观察到,当有问题的 Linux 服务的连接失败时,TLSv1.2 始终是所选的级别。但是,使用 TLSv1.2 时连接并不总是会失败。它们只有 5-10% 的时间会失败。
现在,这是来自没有问题的服务器的交换。其他一切都相同。即连接到相同的数据库、相同的 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
因此,当 Linux JVM 和 SQL Server 之间协商 TLSv1 时,连接始终成功。当协商 TLSv1.2 时,我们会偶尔遇到连接失败。
(注意:Java 7(1.7.0_51)始终协商 TLSv1,这就是为什么我们使用 Java 7 JVM 时从未出现过该问题。)
我们仍未解决的问题是:
为什么从两个不同的 Linux 服务器运行的同一个 Java 8 JVM 总是会协商 TLSv1,但从另一个 Linux 服务器连接时它总是协商 TLSv1.2。
而且为什么在该服务器上,TLSv1.2 协商连接大多数时间都能成功,但并非总是如此?
更新时间:2017 年 6 月 10 日:
微软的这篇文章描述了该问题及其提出的解决方案。
资源:
http://blogs.msdn.com/b/jdbcteam/archive/2008/09/09/the-driver-could-not-built-a-secure-connection-to-sql-server-by-using-secure-套接字层-ssl-加密.aspx
Java 8、JCE 无限强度策略和 TLS 上的 SSL 握手
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
解决方案 3:
如果有人来这里寻找从 PhpStorm 连接数据库的解决方案,只需在 URL 中的端口后添加以下内容:
;encrypt=true;trustServerCertificate=true;
我从这个评论中得到了解决方案:Java 8 上的 SQL Server JDBC 错误:驱动程序无法使用安全套接字层 (SSL) 加密与 SQL Server 建立安全连接
非常感谢!可以确认它在 PhpStorm 2022.1.1 上运行良好。
解决方案 4:
使用 openjdk 11,可以将以下属性添加到连接 URL,以强制使用 SSL
;integratedSecurity=false;encrypt=false;trustServerCertificate=true;
解决方案 5:
添加;encrypt=true;trustServerCertificate=true
到 connection.url 中。示例
jdbc:sqlserver://localhost\SQLEXPRESS:1433;数据库名称=testdb;加密=true;trustServerCertificate=true
并检查 pom 文件中的 java 编译器版本与 maven 的 mssql-jdbc 的 jre 版本是否兼容。像这样
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
和
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>11.2.1.jre8</version>
</dependency>
编译器 1.8 和 jre8
解决方案 6:
应用程序.属性:
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
解决方案 7:
在升级 SQL JDBC 驱动程序之前,请先检查兼容性:
Sqljdbc.jar 需要 JRE 5 并支持 JDBC 3.0 API
Sqljdbc4.jar 需要 JRE 6 并支持 JDBC 4.0 API
Sqljdbc41.jar 需要 JRE 7 并支持 JDBC 4.1 API
Sqljdbc42.jar 需要 JRE 8 并支持 JDBC 4.2 API
来源:https://www.microsoft.com/en-us/download/details.aspx? id=11774
解决方案 8:
感谢@Sunil Kumar 和@Joce。我使用了 jar 和以下语法:
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;"; // here the semicolon will be twice like shown
Connection con = DriverManager.getConnection(myURL);
解决方案 9:
MS SQL JDBC 驱动程序 4.2 版似乎已修复此问题。我创建了一个程序,在其中连接到服务器 1000 次,每次尝试之间暂停 100 毫秒。使用 4.1 版时,我每次都能重现此问题,尽管这种情况偶尔发生。使用 4.2 版时,我无法重现此问题。
解决方案 10:
就像 @2Aguy 写的那样,您可以更改 JVM 参数。就我而言,我无法更改它,而是使用连接字符串“ sslProtocol ”参数,从而降低与 TLSV1 的连接。
连接字符串:jdbc:sqlserver:// <HOST>:<PORT>;encrypt = true;trustServerCertificate = true;sslProtocol = TLSv1;database = <DB NAME>
解决方案 11:
当我将 sqljdbc-4.2.0 jar 更改为 mssql-jdbc-8.4.1 jar 时,问题得到了解决
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>8.4.1.jre8</version>
</dependency>
解决方案 12:
在我的例子中,我有一个使用 3DES_EDE_CBC 算法的 SQL 服务器,该算法在 jdk 1.8 上默认是禁用的,因此检查
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/security/java.security
并消除以下算法:
jdk.tls.disabledAlgorithms=SSLv3、RC4、DES、MD5withRSA、DH 密钥大小 < 1024、\ EC 密钥大小 < 224、3DES_EDE_CBC、anon、NULL
对我有用。
解决方案 13:
我在连接 SQL 数据库时遇到了这个问题。由于 JAR 文件不正确而遇到此问题。
我使用的连接 URL
"jdbc:sqlserver://localhost:8080;databaseName=db_name;encrypt=true;trustServerCertificate=true";
在我使用“sqljdbc4-2.0.jar” JAR文件之前,它对我来说不起作用。
一旦我改变了这个 JAR 文件,它就可以正常工作了
mssql-jdbc-8.4.1.jre8.jar
解决方案 14:
微软最近开源了他们的驱动程序。你可以在 GitHub 上看到mssql-jdbc驱动程序的活动。我猜最新的预览版本是 6.1.5。
您还可以在 maven 上找到所有预览版本。支持 JDK7 和 JDK 8。
解决方案 15:
我在 Windows Server 2012 R2 上也遇到了这个问题,使用 Java 7 的 JDBC 驱动程序 4.0 和 4.1。这篇微软文章将责任归咎于 DHE 密码套件,并建议如果无法升级到 JDBC 驱动程序 4.2,请禁用它们或降低它们的优先级
解决方案 16:
就我而言,问题是因为应用程序设置为使用 spring-boot-ext-security-starter-credhub-credential,而该设置存在一些问题。
因此我从清单文件和 pom 中删除了 credhub,并以不同的方式获取了凭据;然后错误就消失了。
解决方案 17:
如果连接字符串中的服务器名称与 SQL Server SSL 证书中的服务器名称不匹配,则会出现以下错误:驱动程序无法使用安全套接字层 (SSL) 加密与 SQL Server 建立安全连接。错误:“java.security.cert.CertificateException:在安全套接字层 (SSL) 初始化期间无法验证证书中的服务器名称。”
这帮助我解决了这个问题。在服务器名中使用 localhost,最后在 jdbc 连接字符串中更改为与 CN 能够连接的名称相同的名称。
更多信息请参阅:https ://wiki.deepnetsecurity.com/pages/viewpage.action?pageId=1410867
解决方案 18:
我已经在本地环境中修复了该问题,主要包含以下两个步骤。
如果你的项目是由 maven 构建的,请像下面这样切换 JDBC 驱动程序依赖项:
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<version>1.3.1</version>
</dependency>
2.另外替换Driver Class Name:
ru.yandex.clickhouse.ClickHouseDriver
修改 JDBC URL 如下:
jdbc:jtds:sqlserver://xxxx:1433;databaseName=xxx
解决方案 19:
我最近在运行 RedHat 7 的客户服务器上执行 yum 更新后遇到了这个问题。由于上述线程没有帮助我解决问题,因此我发布了此答案。
问题:- RedHat 中的 Yum 更新会自动重新安装 OpenJDK,我的应用程序使用 Oracle JDK。验证默认 JDK:
java version 切换默认版本:
更新替代方案——配置 java
有2个程序提供‘java’。
选择命令
1 java-1.8.0-openjdk.x86_64(/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64/jre/bin/java)
2 /usr/java/jdk1.8.0_181-amd64/jre/bin/java
按 Enter 保留当前选择[+],或键入选择编号:
输入您想要的适当版本的编号,然后按回车键。
解决方案 20:
在使用以下连接字符串创建数据库连接时我也遇到了同样的问题。
DriverManager.getConnection("jdbc:sqlserver://" + host + ":" + port + ";databaseName=" + dbName + ";user=" + userName + ";password=" + password);
按照如下方式更新连接字符串后,它就起作用了。
Connection con = DriverManager.getConnection("jdbc:sqlserver://" + host + ":" + port + ";databaseName=" + dbName + ";encrypt=true;trustServerCertificate=true;user=" + userName + ";password=" + password);
encrypt=true;trustServerCertificate=true
这里我在数据库名称后面添加了。
解决方案 21:
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
对我来说,我在两行之间添加
DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());
Connection con = DriverManager.getConnection(connectionUrl);
因此连接的最终代码将是:
DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection con = DriverManager.getConnection(connectionUrl);
解决方案 22:
如果您是因为 Ignition 8.1+ 错误而来此,并且在本地主机上使用 MSSQL Express,请在“连接 URL”中输入以下内容:jdbc:sqlserver://localhost\SQLEXPRESS; encrypt=true;trustServerCertificate=true;
URL 设置
有效连接
解决方案 23:
setTrustServerCertificate(true);
对我有用。
解决方案 24:
我们可以在以下页面中找到这个问题的答案:
答案:"; integratedSecurity =true;" + " encrypt =true; trustServerCertificate =true";"
解决方案 25:
对我来说最终有用的是更新到最新的 mssql jdbc 驱动程序,然后确保我使用 SQL 服务器的 SSL 证书上显示的完全限定域名。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件