将 TLSv1.2 与 Microsoft JDBC 驱动程序和 Oracle JRE 7 结合使用
Using TLSv1.2 with Microsoft JDBC driver and Oracle JRE 7
有一个在 Oracle JRE 7 上运行并使用标准 Microsoft jdbc 驱动程序与 Microsoft SQL 服务器交换数据的应用程序。
在部署此应用程序的公司决定将数据库更新到 SQL Server 2017 并禁用所有低于 TLSv1.2 的 TLS 协议之前,它工作正常。现在应用程序在尝试连接到 SQL 服务器时出现以下错误:
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 did not return a response. The connection has been closed. ClientConnectionId:5892fb2f-67c4-45f5-a01d-cc7c1db8f69e".
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1667)
at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1668)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:1323)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:991)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:827)
at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:1012)
at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:131)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:156)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:145)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolPooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:200)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1086)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1073)
at com.mchange.v2.resourcepool.BasicResourcePool.access0(BasicResourcePool.java:44)
at com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1810)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:648)
Caused by: java.io.IOException: SQL Server did not return a response. The connection has been closed. ClientConnectionId:5892fb2f-67c4-45f5-a01d-cc7c1db8f69e
at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.ensureSSLPayload(IOBuffer.java:651)
at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.readInternal(IOBuffer.java:708)
at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.read(IOBuffer.java:700)
at com.microsoft.sqlserver.jdbc.TDSChannel$ProxyInputStream.readInternal(IOBuffer.java:895)
at com.microsoft.sqlserver.jdbc.TDSChannel$ProxyInputStream.read(IOBuffer.java:883)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:442)
at sun.security.ssl.InputRecord.read(InputRecord.java:480)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:927)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1618)
... 13 more
我已经使用 -Djavax.net.debug=ssl:handshake:verbose JVM 选项启用了 SSL 握手日志记录,我可以看到 jdbc 驱动程序正在尝试使用 TLSv1:
*** ClientHello, TLSv1
我是支持此应用程序的开发人员,我有源代码并且可以对其进行更改。
一段时间后,此应用程序将移植到 JRE 8,但这需要付出大量努力,现在最好有一些解决方法。
我在搜索解决方案时发现的内容:
将 JRE 更新到 1.7.0_131。但是 131 更新仅适用于拥有 Oracle Java 支持合同的用户。 Oracle JDK 7 的最新免费更新是 1.7.0_80.
https://social.technet.microsoft.com/Forums/en-US/fb80c86c-97a2-4e35-b998-1030a5c77580/does-jdbc-driver-support-for-tlsv12-with-jre-17
似乎正是我的问题。一位用户找到了解决方案,但它仅适用于 IBM JDK。
我最终得到了丑陋的 hakish 解决方案,它使用内部 jre 类 强制使用 TLS 1.2。我在建立 jdbc 连接之前调用此函数:
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import javax.net.ssl.SSLContextSpi;
import sun.security.jca.GetInstance;
import sun.security.jca.ProviderList;
import sun.security.jca.Providers;
public static void enableTLSv12ForMssqlJdbc() throws NoSuchAlgorithmException
{
ProviderList providerList = Providers.getProviderList();
GetInstance.Instance instance = GetInstance.getInstance("SSLContext", SSLContextSpi.class, "TLS");
for (Provider provider : providerList.providers())
{
if (provider == instance.provider)
{
provider.put("Alg.Alias.SSLContext.TLS", "TLSv1.2");
}
}
}
现在我看到 jdbc 驱动程序使用 TLSv1.2 并成功连接到 SQL Server 2017
*** ClientHello, TLSv1.2
有一个在 Oracle JRE 7 上运行并使用标准 Microsoft jdbc 驱动程序与 Microsoft SQL 服务器交换数据的应用程序。
在部署此应用程序的公司决定将数据库更新到 SQL Server 2017 并禁用所有低于 TLSv1.2 的 TLS 协议之前,它工作正常。现在应用程序在尝试连接到 SQL 服务器时出现以下错误:
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 did not return a response. The connection has been closed. ClientConnectionId:5892fb2f-67c4-45f5-a01d-cc7c1db8f69e".
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1667)
at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1668)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:1323)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:991)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:827)
at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:1012)
at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:131)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:156)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:145)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolPooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:200)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1086)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1073)
at com.mchange.v2.resourcepool.BasicResourcePool.access0(BasicResourcePool.java:44)
at com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1810)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:648)
Caused by: java.io.IOException: SQL Server did not return a response. The connection has been closed. ClientConnectionId:5892fb2f-67c4-45f5-a01d-cc7c1db8f69e
at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.ensureSSLPayload(IOBuffer.java:651)
at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.readInternal(IOBuffer.java:708)
at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.read(IOBuffer.java:700)
at com.microsoft.sqlserver.jdbc.TDSChannel$ProxyInputStream.readInternal(IOBuffer.java:895)
at com.microsoft.sqlserver.jdbc.TDSChannel$ProxyInputStream.read(IOBuffer.java:883)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:442)
at sun.security.ssl.InputRecord.read(InputRecord.java:480)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:927)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1618)
... 13 more
我已经使用 -Djavax.net.debug=ssl:handshake:verbose JVM 选项启用了 SSL 握手日志记录,我可以看到 jdbc 驱动程序正在尝试使用 TLSv1:
*** ClientHello, TLSv1
我是支持此应用程序的开发人员,我有源代码并且可以对其进行更改。 一段时间后,此应用程序将移植到 JRE 8,但这需要付出大量努力,现在最好有一些解决方法。
我在搜索解决方案时发现的内容:
将 JRE 更新到 1.7.0_131。但是 131 更新仅适用于拥有 Oracle Java 支持合同的用户。 Oracle JDK 7 的最新免费更新是 1.7.0_80.
https://social.technet.microsoft.com/Forums/en-US/fb80c86c-97a2-4e35-b998-1030a5c77580/does-jdbc-driver-support-for-tlsv12-with-jre-17
似乎正是我的问题。一位用户找到了解决方案,但它仅适用于 IBM JDK。
我最终得到了丑陋的 hakish 解决方案,它使用内部 jre 类 强制使用 TLS 1.2。我在建立 jdbc 连接之前调用此函数:
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import javax.net.ssl.SSLContextSpi;
import sun.security.jca.GetInstance;
import sun.security.jca.ProviderList;
import sun.security.jca.Providers;
public static void enableTLSv12ForMssqlJdbc() throws NoSuchAlgorithmException
{
ProviderList providerList = Providers.getProviderList();
GetInstance.Instance instance = GetInstance.getInstance("SSLContext", SSLContextSpi.class, "TLS");
for (Provider provider : providerList.providers())
{
if (provider == instance.provider)
{
provider.put("Alg.Alias.SSLContext.TLS", "TLSv1.2");
}
}
}
现在我看到 jdbc 驱动程序使用 TLSv1.2 并成功连接到 SQL Server 2017
*** ClientHello, TLSv1.2