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

新手上路,请多包涵

In the latest update to the JDK in April 2021 ( 11.0.11+9-0ubuntu2~18.04 ) support for TLSv1 and TLSv1.1 was dropped, presumably because since March 2021 those versions are no longer supported . 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 文件是解决此问题的良好长期解决方案!

原文由 bersling 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

正如@skelwa 已经评论过的,您需要在连接字符串中添加 enabledTLSProtocols=TLSv1.2 配置属性来解决您的问题。

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

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

对于 r2dbc ,您需要使用 tlsVersion=TLSv1.2 代替。

对于 Connector/J v8.0.28 enabledTLSProtocols 已重命名为 tlsVersions (见 注释)。但是,原始名称仍然作为别名。


剩下的问题是:

为什么 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 连接属性 enabledTLSProtocols 显式启用它们(例如,设置 enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2)。


警告: 请注意,建议编辑 jdk.tls.disabledAlgorithms 内部 jre/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)
    ...

原文由 Kristianmitk 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

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

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

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

原文由 Ankur Raiyani 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题