为什么Java在最新的JDK更新后不能连接到MySQL 5.7,应该如何修复?(ssl.SSLHandshakeException:没有合适的协议)

2022-08-31 16:39:05

在2021年4月对JDK的最新更新中()支持并被删除,可能是因为自2021年3月以来不再支持这些版本。文件中的差异可以明显看出这一点:11.0.11+9-0ubuntu2~18.04TLSv1TLSv1.1java.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上运行。现在,根据我的理解,如上所述,MySQL 5.7支持TLSv1.2。此外,在运行时,我们得到哪个建议是支持的。5.7.33-0ubuntu0.18.04.1SHOW VARIABLES LIKE 'tls_version';TLSv1,TLSv1.1,TLSv1.2TLSv1.2

那么问题来了,为什么JDK和MySQL不就使用达成一致,我们能做些什么来让他们与之通信?TLSv1.2TLSv1.2

注意:我不认为按照其他线程中的建议更改文件是解决此问题的良好长期解决方案!java.security


答案 1

正如@skelwa已经注释的那样,您需要在连接字符串中添加配置属性才能解决问题。enabledTLSProtocols=TLSv1.2

Connector/J 的完整连接字符串可能如下所示:

jdbc:mysql://<host>:<port>/<dbname>?enabledTLSProtocols=TLSv1.2

对于 r2dbc,您需要改用。tlsVersion=TLSv1.2

对于连接器/J,v8.0.28 已重命名为(请参阅注释)。但是,原始名称仍保留为别名。enabledTLSProtocolstlsVersions


剩下的问题是:

为什么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 Server 存在兼容性问题,Connector/J 默认情况下不启用与 TLSv1.2 及更高版本的连接。当连接到限制连接以使用这些更高 TLS 版本的服务器时,请通过设置已启用的 Connector/J 连接属性TLSProtocols 来显式启用它们(例如,设置 enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2)。


警告:请注意,建议在 内部编辑的解决方案会对您的应用程序构成安全风险,并且更改其中的任何内容可能会产生严重影响!禁用这些协议是有原因的,不应该简单地从该列表中删除所有内容,甚至只是删除部分内容。jdk.tls.disabledAlgorithmsjre/lib/security


注意:如果您想从 JDK 获得更多低级见解来调试问题,可以通过将以下配置传递给 java comand 来启用 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)
    ...

答案 2

我刚刚添加了useSSL=false,它对我有用。

jdbc:mysql://<host>:<port>/<dbname>?useSSL=false

我有JDK 8,MySQL 5.7和mysql-connector-java lib版本5.1.38

当您只想在本地环境中快速执行(而不是暂存/测试/生产)时,这很有用


推荐