配置useSSL=true连接Azure MySQL遇SHA1withRSA算法限制报错求助
问题场景
使用SymmetricDS的dbsql连接Azure MySQL数据库,按云环境要求设置useSSL=true后,出现以下错误:
java.security.cert.CertPathValidatorException: 签名算法检查失败: SHA1withRSA
at java.base/sun.security.provider.certpath.AlgorithmChecker.check(AlgorithmChecker.java:231) at java.base/sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(SSLContextImpl.java:1553)
[包装异常] java.security.cert.CertificateException: 证书不符合算法约束
at java.base/sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(SSLContextImpl.java:1557) at java.base/sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(SSLContextImpl.java:1484) at java.base/sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:1431) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:631)
[包装异常] javax.net.ssl.SSLHandshakeException: 证书不符合算法约束
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:130) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:378) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:316) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:647) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:467) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:363) at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:393) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:476) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:447) at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:201) at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:172) at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1506) at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1421) at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:455) at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:426) at com.mysql.cj.protocol.ExportControlled.performTlsHandshake(ExportControlled.java:347) at com.mysql.cj.protocol.StandardSocketFactory.performTlsHandshake(StandardSocketFactory.java:194) at com.mysql.cj.protocol.a.NativeSocketConnection.performTlsHandshake(NativeSocketConnection.java:101) at com.mysql.cj.protocol.a.NativeProtocol.negotiateSSLConnection(NativeProtocol.java:308)
[包装异常] com.mysql.cj.exceptions.CJCommunicationsException: 通信链路失败
上次成功发送到服务器的数据包是0毫秒前,驱动未从服务器收到任何数据包。
at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61) at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105) at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:151) at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:167) at com.mysql.cj.protocol.a.NativeProtocol.negotiateSSLConnection(NativeProtocol.java:317) at com.mysql.cj.protocol.a.NativeAuthenticationProvider.connect(NativeAuthenticationProvider.java:204) at com.mysql.cj.protocol.a.NativeProtocol.connect(NativeProtocol.java:1369) at com.mysql.cj.NativeSession.connect(NativeSession.java:133) at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:949) at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:819)
[包装异常] com.mysql.cj.jdbc.exceptions.CommunicationsException: 通信链路失败
上次成功发送到服务器的数据包是0毫秒前,驱动未从服务器收到任何数据包。
at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:829) at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:449) at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:242) at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:198) at org.apache.commons.dbcp2.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:52) at org.apache.commons.dbcp2.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:374) at org.apache.commons.dbcp2.BasicDataSource.validateConnectionFactory(BasicDataSource.java:106) at org.apache.commons.dbcp2.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:649)
[包装异常] java.sql.SQLException: 无法创建PoolableConnectionFactory(通信链路失败
解决方法
1. 升级MySQL JDBC驱动版本
使用8.0.28及以上版本的mysql-connector-java驱动,新版本对TLS协议和证书算法的支持更完善,能自动适配Azure MySQL的安全要求,避免旧驱动与现代证书算法不兼容的问题。
2. 优化JDBC连接参数
在原有useSSL=true的基础上,添加以下参数:
enabledTLSProtocols=TLSv1.2,TLSv1.3&sslMode=REQUIRED&trustServerCertificate=false
enabledTLSProtocols:强制使用TLS 1.2/1.3协议,这两个协议默认使用更安全的签名算法,规避SHA1withRSA的限制sslMode=REQUIRED:确保SSL连接强制启用,符合Azure MySQL的安全要求trustServerCertificate=false:如果已导入Azure的CA证书到Java信任库,保持这个参数以验证证书有效性;若临时测试,可设为true(不推荐生产环境)
3. 导入Azure MySQL官方CA证书
Azure MySQL使用DigiCertGlobalRootCA作为根证书,下载该证书后,通过keytool导入到Java的信任库中:
keytool -importcert -alias AzureMySQLCA -file DigiCertGlobalRootCA.crt.pem -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
导入后,Java会信任Azure MySQL的证书,避免因证书不被信任触发的算法约束检查。
4. 调整Java安全策略(仅在必要时使用)
如果以上方法无效,可临时修改Java的安全配置文件($JAVA_HOME/jre/lib/security/java.security):
- 找到
jdk.certpath.disabledAlgorithms配置项,将SHA1withRSA从禁用列表中移除 - 找到
jdk.tls.disabledAlgorithms配置项,确保SHA1withRSA不在禁用范围内
注意:修改全局安全策略会降低Java环境的安全性,仅在无法通过其他方式解决时使用,用完后建议恢复配置。
内容的提问来源于stack exchange,提问作者Jeetendra Nigam

