【问题标题】:sqljdbc4.jar - cannot connect to MSSQL server instance - SSL error?sqljdbc4.jar - 无法连接到 MSSQL 服务器实例 - SSL 错误?
【发布时间】:2025-12-30 00:00:16
【问题描述】:

我正在使用此代码在 Ubuntu 机器上使用 sqljdbc4.jar 从 OpenJDK1.8 连接到 MSSQL 2012 实例:

public static DataSource getMsSqlPoolSource(String server, String database, String user, String password) throws ClassNotFoundException {
    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

    String connectionString = "jdbc:sqlserver://" + server + ";databaseName=" + database + ";sendStringParametersAsUnicode=false;";
    System.out.println("Connection String for MSSQL is:: " + connectionString);
    org.apache.commons.dbcp2.ConnectionFactory factory = new DriverManagerConnectionFactory(connectionString, user, password);
    PoolableConnectionFactory poolFactory = new PoolableConnectionFactory(factory, null);
    ObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(poolFactory);
    poolFactory.setPool(connectionPool);
    PoolingDataSource<PoolableConnection> dataSource = new PoolingDataSource<>(connectionPool);
    return dataSource;
}

这工作了三年,直到今天。

如果我现在尝试从同一个 Ubuntu 机器连接到与过去三年相同的 MSSQL 2012 实例,我会遇到异常:

2021-07-31 10:01:07.125 ERROR vsCallLogSyncOnVerinet - SQL ERROR:: 1jyg0yezlh46 - invalid database address: jdbc:sqlserver://172.16.1.244;databaseName=my_DB;sendStringParametersAsUnicode=false;
Security providers: [SUN version 1.8, SunRsaSign version 1.8, SunEC version 1.8, SunJSSE version 1.8, SunJCE version 1.8, SunJGSS version 1.8, SunSASL version 1.8, XMLDSig version 1.8, SunPCSC version 1.8]
SSLContext provider info: Sun JSSE provider(PKCS12, SunX509/PKIX key/trust factories, SSLv3/TLSv1/TLSv1.1/TLSv1.2/TLSv1.3)
SSLContext provider services:
[SunJSSE: KeyFactory.RSA -> sun.security.rsa.RSAKeyFactory$Legacy
  aliases: [1.2.840.113549.1.1, OID.1.2.840.113549.1.1]
, SunJSSE: KeyPairGenerator.RSA -> sun.security.rsa.RSAKeyPairGenerator$Legacy
  aliases: [1.2.840.113549.1.1, OID.1.2.840.113549.1.1]
, SunJSSE: Signature.MD2withRSA -> sun.security.rsa.RSASignature$MD2withRSA
  aliases: [1.2.840.113549.1.1.2, OID.1.2.840.113549.1.1.2]
, SunJSSE: Signature.MD5withRSA -> sun.security.rsa.RSASignature$MD5withRSA
  aliases: [1.2.840.113549.1.1.4, OID.1.2.840.113549.1.1.4]
, SunJSSE: Signature.SHA1withRSA -> sun.security.rsa.RSASignature$SHA1withRSA
  aliases: [1.2.840.113549.1.1.5, OID.1.2.840.113549.1.1.5, 1.3.14.3.2.29, OID.1.3.14.3.2.29]
, SunJSSE: Signature.MD5andSHA1withRSA -> sun.security.ssl.RSASignature
, SunJSSE: KeyManagerFactory.SunX509 -> sun.security.ssl.KeyManagerFactoryImpl$SunX509
, SunJSSE: KeyManagerFactory.NewSunX509 -> sun.security.ssl.KeyManagerFactoryImpl$X509
  aliases: [PKIX]
, SunJSSE: TrustManagerFactory.SunX509 -> sun.security.ssl.TrustManagerFactoryImpl$SimpleFactory
, SunJSSE: TrustManagerFactory.PKIX -> sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory
  aliases: [SunPKIX, X509, X.509]
, SunJSSE: SSLContext.TLSv1 -> sun.security.ssl.SSLContextImpl$TLS10Context
  aliases: [SSLv3]
, SunJSSE: SSLContext.TLSv1.1 -> sun.security.ssl.SSLContextImpl$TLS11Context
, SunJSSE: SSLContext.TLSv1.2 -> sun.security.ssl.SSLContextImpl$TLS12Context
, SunJSSE: SSLContext.TLSv1.3 -> sun.security.ssl.SSLContextImpl$TLS13Context
, SunJSSE: SSLContext.TLS -> sun.security.ssl.SSLContextImpl$TLSContext
  aliases: [SSL]
, SunJSSE: SSLContext.Default -> sun.security.ssl.SSLContextImpl$DefaultSSLContext
, SunJSSE: KeyStore.PKCS12 -> sun.security.pkcs12.PKCS12KeyStore
]
java.ext.dirs: /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext:/usr/java/packages/lib/ext

我最近为两个域添加了一些证书到 OpenJDK1.8 证书存储中,这两个域与我的本地 B 类上的直接通过 ip 连接无关,我通过我的 B 类 LAN 连接到本地 MSSQL 实例。

为什么 MSSQL JDBC 驱动程序突然导致涉及证书的明显异常,并拒绝连接?

我不希望 JDBC 驱动程序使用我添加的任何证书,它必须正常进行并忽略它们?

我有另一台 Ubuntu 机器使用相同的 JDK 版本和相同的 JDBC 驱动程序,以及包含我的应用程序的相同 JAR,它在 OpenJDK1.8 证书存储中没有任何用户添加的证书,它可以连接到相同的 MSSQL 服务器使用 JDBC 驱动程序和相同的连接字符串,没问题。

为什么要为我从 Java 应用程序连接到的 Internet 上的不相关域添加 SSL 证书,现在显然会导致该应用程序中的 MSSQL Java JDBC 驱动程序尝试使用来自 OpenJDK1.8 证书存储的随机 SSL 证书连接到本地by-ip B类网络上的本地MSSQSL服务器?

证书是这样添加的:

/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/keytool -trustcacerts -keystore /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts -storepass changeit -noprompt -importcert -alias lets-encrypt-x3-cross-signed -file lets-encrypt-x3-cross-signed.der

/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/keytool -trustcacerts -keystore /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts -storepass changeit -noprompt -importcert -alias lets-encrypt-x3-cross-signed2 -file isrg-root-x1-cross-signed.der

/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/keytool -trustcacerts -keystore /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts -storepass changeit -noprompt -importcert -alias lets-encrypt-x3-cross-signed3 -file lets-encrypt-r3.der

编辑:设法确定上面添加的 SSH 证书不是问题 - 如果我将它们从信任库中删除,问题仍然存在,与上面的 JDBC 连接完全相同。因此,加载的 SSH 证书对 JDBC 连接问题没有影响 e。 G。连接尝试作为无效的数据库地址返回。

【问题讨论】:

  • 您确定您没有意外删除现有证书吗?您最近是否在两台机器上运行过更新?
  • 您好,谢谢您的回复。我实际上只是为域添加了 .der 证书文件。一台机器是最近安装的带有 OpenJDK1.8 的全新 Ubuntu 20.21,另一台是大约 3 个月前更新的 Ubuntu 20.21,直到那时为止,使用 OpenJDK1.8.... 旧安装的机器仍在工作,新的昨天加载的证书是 JDBC 实例无法连接的。
  • 尝试记录 SSL 调试(使用 -Djavax.net.debug=all 启动您的应用程序),另请参阅 Debugging SSL/TLS Connections。此外,最近的 Java 版本默认禁用了一些较旧的 TLS 版本。确保两者的jre/lib/security/java.security 配置文件相同。
  • 谢谢 Mark 尝试过,我只是将数万行记录到控制台,看起来很正常(至少有几百行。)这就是我从应用程序建立两个 SSL 连接的事情到两台服务器,并且在两个实例中都能 100% 工作 - 较旧的 Ubuntu 实例应用程序和较新的 Ubuntu 实例应用程序 - 实际上只是 MSSQL JDBC 连接在较新的 Ubuntu 实例上失败,其中一个看起来是 JDBC 驱动程序试图使用 MSSQL 服务器端不支持的证书与 MSSQL 服务器建立 SSL 连接。
  • 我建议仅创建一个基本应用程序来重现该问题,如果您可以重现它,则启用该日志记录。它应该查明 SSL 握手失败的地方(假设是失败的地方)。

标签: java sql-server ssl jdbc


【解决方案1】:

在 Mark Rotteveel 和 AlwaysLearning 的帮助下解决了这个问题。

这与我加载到 OpenJDK1.8 信任库中的 SSL 证书无关。

问题是三方面的。

首先,在我的 Netbeans 11 项目中,在“Dependencies”文件夹中,我有一个名为

MSSQL-4.0.jar

这显然是由该项目的前一位开发人员手动放置的。

我删除了这个文件 - 我不知道正在使用哪个驱动程序,因为我有一个如上所述的 maven 工件,还有 MSSQL JDBC 驱动程序。

其次,AlwaysLearning 好心地指出,我与 MSSQL 的连接异常是指 SQLLite(不是 MSSQL),并且 SQLLite 驱动程序报告了无效数据库地址的异常,而不是 MSSQL 驱动程序。

核心问题是,由于某种原因,当我尝试使用上述源代码连接到 MSSQL 时,MSSQL JDBC 驱动程序正在尝试与 MSSQL 建立 SQLLite 连接。

这就是我不断得到的原因

java.sql.SQLException: invalid database address:jdbc:sqlserver://172.17.12.14;databaseName=DB;sendStringParametersAsUnicode=false;

当然,SQLLite 连接协议永远不会在 MSSQL 服务器上工作......

第三,与 MSSQL 的连接尝试的异常随后更改为指 MSSQL 服务器对连接使用过时的 TLS 加密,而我的客户端在 JDBC 端拒绝了这一事实 - 见上文。然后 Mark Rotteveel 协助编辑文件

/etc/java-8-openjdk/security/java.security

在我的 Ubuntu 20.11 LTS OpenJKD1.8 上安装以降低 TLS 的安全性,以便我的 OpenJDK1.8 实例允许 TLS 加密级别是我尝试连接的相当旧的 MSSQL 实例所需要的。

在 /etc/java-8-openjdk/security/java.security 我改了行

jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
    DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
    include jdk.disabled.namedCurves

jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, \
    DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
    include jdk.disabled.namedCurves

总而言之,在从我的 NetBeans 项目的“依赖项”文件夹中删除虚假的 MSSQL-4.0.jar 之后,我还注释掉了 SQLLite 的 Maven 工件(因为它不再在我的项目中使用,并且是一个遗留库)。一旦 SQLLite 库在下一次编译中被 Maven 删除,并且我编辑了 java.security 文件,如上所述,生成的 .JAR 能够从我的 Ubuntu 机器连接到 MSSQL 服务器,之后我降低了 / 中的安全要求etc/java-8-openjdk/security/java.security 并使用 OpenJDK1.8 安装在 Ubuntu 机器上重新启动我的应用程序。

这是因为 MSSQL JDBC 驱动程序现在使用“真正的”MSSQL 协议来尝试从我的 Ubuntu 机器连接到 MSSQL 服务器,而不是尝试使用 SQLLite 协议连接到 MSSQL 服务器,-并且-在更改 java.security 后,JDBC 驱动程序被允许与 MSSQL 服务器通信“足够老”的 TLS 版本。

希望这对其他人有所帮助。

斯蒂芬

【讨论】:

  • 我们在 sqlserver 2012 上遇到了同样的 tls 问题。该版本已停产。适当的长期解决方案是升级到受支持的 SQL Server 版本。
  • 另外,这就是为什么您不应该对实际问题做出假设的原因,因为您通常是错误的(或者您会自己解决)只是客观地描述症状并回答其他问题。
  • @ThorbjørnRavnAndersen 谢谢你,先生,我会记住这一点,我的假设在这里肯定有问题。感谢您抽出宝贵时间提供帮助/评论!亲切的问候。