为什么Java在最新的JDK更新后无法连接到MySQL5.7,应该如何修复?(ssl.SSLHandshakeException:没有合适的协议)
在四月2021(最新更新到JDK 11.0.11+9-0ubuntu2~18.04),用于支持TLSv1和TLSv1.1被放弃了,可能是因为2021年3月份以来的版本不再支持。从java.security文件中的差异可以看出这一点:
前:
jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024,
EC keySize < 224, 3DES_EDE_CBC, anon, NULL,
include jdk.disabled.namedCurves
后:
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
这也在这篇 SO 帖子中进行了讨论:SSLHandShakeException No Appropriate Protocol。在该线程中,自更新的 JDK 版本以来的最后几天还出现了更多答案。
这次更新JDK后,我们收到错误
java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
与c3p0.
切换到后,hikari我们得到了一个更有意义的错误:
ERROR [2021-04-29 16:21:16,426] com.zaxxer.hikari.pool.HikariPool: HikariPool-1 - Exception during pool initialization.
! javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
我们在 MySQL 上运行5.7.33-0ubuntu0.18.04.1。现在,在我的理解中描述这里时,MySQL 5.7支持TLSv1.2工作。此外,在运行时,SHOW VARIABLES LIKE 'tls_version';我们会得到支持的TLSv1,TLSv1.1,TLSv1.2建议TLSv1.2。
那么问题来了,为什么 JDK 和 MySQL 不就使用达成一致TLSv1.2,我们可以做些什么,让它们与之通信TLSv1.2?
注意:我不认为java.security按照另一个线程中的建议更改文件是解决此问题的良好长期解决方案!
回答
正如@skelwa 已经评论过的,您需要enabledTLSProtocols=TLSv1.2在连接字符串中添加配置属性来解决您的问题。完整的连接字符串可能如下所示:
jdbc:mysql://<host>:<port>/<dbname>?enabledTLSProtocols=TLSv1.2
剩下的问题是:
为什么 JDK 和 MySQL 不同意使用TLSv1.2?
尽管双方实际上都支持 TLSv1.2,但您遇到的问题是由 Connector/J 的默认行为引入的。出于兼容性原因,Connector/J 默认不启用 TLSv1.2 及更高版本。因此,必须明确启用它。
请参阅以下说明:
对于使用 JDBC API 连接到 MySQL Community Server 5.6 和 5.7 时的 Connector/J 8.0.18 及更早版本:由于与使用 yaSSL 编译的 MySQL 服务器的兼容性问题,默认情况下,Connector/J 不启用与 TLSv1.2 及更高版本的连接。当连接到限制连接使用那些更高 TLS 版本的服务器时,通过设置 Connector/J 连接属性 enabledTLSProtocols(例如,设置 enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2)来显式启用它们。
警告:请注意,建议在内部编辑的解决方案会给您的应用程序带来安全风险,并且更改其中的任何内容可能会产生严重影响!这些协议被禁用是有原因的,不应简单地从该列表中删除所有内容甚至部分内容。jdk.tls.disabledAlgorithmsjre/lib/security
注意:如果您想从 JDK 获得更多低级见解来调试您的问题,您可以通过将以下配置传递给 java 命令来启用 ssl 调试日志:
-Djavax.net.debug=ssl,handshake
甚至
-Djavax.net.debug=all
在您的情况下,您将看到如下内容:
...(HANDSHAKE_FAILURE): Couldn't kickstart handshaking (
"throwable" : {
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at java.base/sun.security.ssl.HandshakeContext.<init>(HandshakeContext.java:170)
at java.base/sun.security.ssl.ClientHandshakeContext.<init>(ClientHandshakeContext.java:98)
...