Java 8 上的 SQL Server JDBC 错误:驱动程序无法使用安全套接字层 (SSL) 加密与 SQL Server 建立安全连接

2024-10-14 08:39:00
admin
原创
76
摘要:问题描述:使用 Microsoft JDBC Driver 版本连接到 SQL Server 数据库时出现以下错误:com.microsoft.sqlserver.jdbc.SQLServerException:驱动程序无法使用安全套接字层 (SSL) 加密与 SQL Server 建立安全连接。错误:“SQ...

问题描述:

使用 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 时从未出现过该问题。)

我们仍未解决的问题是:

  1. 为什么从两个不同的 Linux 服务器运行的同一个 Java 8 JVM 总是会协商 TLSv1,但从另一个 Linux 服务器连接时它总是协商 TLSv1.2。

  2. 而且为什么在该服务器上,TLSv1.2 协商连接大多数时间都能成功,但并非总是如此?

更新时间:2017 年 6 月 10 日:
微软的这篇文章描述了该问题及其提出的解决方案。

资源:

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-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 时,问题得到了解决

&lt;dependency>
      &lt;groupId>com.microsoft.sqlserver&lt;/groupId>
      &lt;artifactId>mssql-jdbc&lt;/artifactId>
      &lt;version>8.4.1.jre8&lt;/version>
&lt;/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

 &quot;jdbc:sqlserver://localhost:8080;databaseName=db_name;encrypt=true;trustServerCertificate=true&quot;;

在我使用“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:

我已经在本地环境中修复了该问题,主要包含以下两个步骤。

  1. 如果你的项目是由 maven 构建的,请像下面这样切换 JDBC 驱动程序依赖项:

&lt;dependency>
  &lt;groupId>net.sourceforge.jtds&lt;/groupId>
  &lt;artifactId>jtds&lt;/artifactId>
  &lt;version>1.3.1&lt;/version>
&lt;/dependency>

2.另外替换Driver Class Name:

ru.yandex.clickhouse.ClickHouseDriver
  1. 修改 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(&quot;jdbc:sqlserver://&quot; + host + &quot;:&quot; + port + &quot;;databaseName=&quot; + dbName + &quot;;user=&quot; + userName + &quot;;password=&quot; + password);

按照如下方式更新连接字符串后,它就起作用了。

Connection con = DriverManager.getConnection(&quot;jdbc:sqlserver://&quot; + host + &quot;:&quot; + port + &quot;;databaseName=&quot; + dbName + &quot;;encrypt=true;trustServerCertificate=true;user=&quot; + userName + &quot;;password=&quot; + password);

encrypt=true;trustServerCertificate=true这里我在数据库名称后面添加了。

解决方案 21:

Class.forName(&quot;com.microsoft.sqlserver.jdbc.SQLServerDriver&quot;);
对我来说,我在两行之间添加

DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());

Connection con = DriverManager.getConnection(connectionUrl);

因此连接的最终代码将是:

    DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());
    Class.forName(&quot;com.microsoft.sqlserver.jdbc.SQLServerDriver&quot;);
    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:

我们可以在以下页面中找到这个问题的答案:

https://learn.microsoft.com/en-us/sql/connect/jdbc/connecting-with-ssl-encryption?view=sql-server-ver16

答案:"; integratedSecurity =true;" + " encrypt =true; trustServerCertificate =true";"

解决方案 25:

对我来说最终有用的是更新到最新的 mssql jdbc 驱动程序,然后确保我使用 SQL 服务器的 SSL 证书上显示的完全限定域名。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用