为什么在最新的 JDK 更新后 Java 无法连接到 MySQL 5.7,应该如何修复? (ssl.SSLHandshakeException:没有合适的协议)
Why can Java not connect to MySQL 5.7 after the latest JDK update and how should it be fixed? (ssl.SSLHandshakeException: No appropriate protocol)
在 2021 年 4 月 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 post: 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
。根据我的理解,here、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
配置 属性 才能解决您的问题。
Connector/J 的完整连接字符串可能如下所示:
jdbc:mysql://<host>:<port>/<dbname>?enabledTLSProtocols=TLSv1.2
对于 r2dbc,您需要使用 tlsVersion=TLSv1.2
。
对于 Connector/J v8.0.28 enabledTLSProtocols
已重命名为 tlsVersions
(参见 note)。但是,原始名称仍然作为别名。
剩下的问题是:
为什么 JDK 和 MySQL 不同意使用 TLSv1.2
?
虽然双方实际上都支持 TLSv1.2,但您遇到的问题是由 Connector/J 的默认行为引入的。出于兼容性原因,Connector/J 默认不启用 TLSv1.2 及更高版本。因此,必须明确启用它。
见下文note:
For Connector/J 8.0.18 and earlier when connecting to MySQL Community
Server 5.6 and 5.7 using the JDBC API: Due to compatibility issues
with MySQL Server compiled with yaSSL, Connector/J does not enable
connections with TLSv1.2 and higher by default. When connecting to
servers that restrict connections to use those higher TLS versions,
enable them explicitly by setting the Connector/J connection property
enabledTLSProtocols (e.g., set
enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2).
警告:请注意 解决方案 建议在 jre/lib/security
中编辑 jdk.tls.disabledAlgorithms
构成 安全风险 对您的应用程序和更改那里的任何内容可能会产生严重影响!
这些协议被禁用是有原因的,不应该简单地从该列表中删除所有内容,甚至只是部分内容。
注意: 如果您想从 JDK 获得更多底层见解来调试您的问题,您可以通过将以下配置传递给java 命令:
-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)
...
您可以执行以下步骤:
- 打开 java.security 文件。 (在 jre/lib/security 文件夹下)
- 找到以下行:
jdk.tls.disabledAlgorithms
- 评论完整的行。
在此之后尝试 运行 应该可以。
或者,如果您只需要特定算法,请将其从禁用列表中删除。
您可以在配置中发送它并在 java.security 文件中注释
jdbc:mysql://<host>:<port>/<dbname>?enabledTLSProtocols=TLSv1.2
我刚刚添加了 useSSL=false,它对我有用。
jdbc:mysql://<host>:<port>/<dbname>?useSSL=false
我有 JDK 8、MySQL 5.7 和 mysql-connector-java 库版本 5.1.38
这在您只想在本地环境中快速执行时很有用(不是 staging/test/prod)
我来这里是因为我遇到了同样的问题,但不幸的是,
jdbc:mysql://host:port/dbname?enabledTLSProtocols=TLSv1.2
对我不起作用,因为我使用的是 r2dbc。经过一些调试我发现参数的名称必须是 tlsVersion
而不是,所以你可以使用,例如:
spring.r2dbc.url=r2dbc:mysql://host:port/dname?tlsVersion=TLSv1.2
由于 mysql-connector-java-5.1.40-bin.jar 和 OpenJDK 1.8 版本较旧,升级到 5.1 后,我遇到了这个问题.49 版本解决了我的问题
在 2021 年 4 月 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 post: 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
。根据我的理解,here、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
配置 属性 才能解决您的问题。
Connector/J 的完整连接字符串可能如下所示:
jdbc:mysql://<host>:<port>/<dbname>?enabledTLSProtocols=TLSv1.2
对于 r2dbc,您需要使用 tlsVersion=TLSv1.2
。
对于 Connector/J v8.0.28 enabledTLSProtocols
已重命名为 tlsVersions
(参见 note)。但是,原始名称仍然作为别名。
剩下的问题是:
为什么 JDK 和 MySQL 不同意使用 TLSv1.2
?
虽然双方实际上都支持 TLSv1.2,但您遇到的问题是由 Connector/J 的默认行为引入的。出于兼容性原因,Connector/J 默认不启用 TLSv1.2 及更高版本。因此,必须明确启用它。
见下文note:
For Connector/J 8.0.18 and earlier when connecting to MySQL Community Server 5.6 and 5.7 using the JDBC API: Due to compatibility issues with MySQL Server compiled with yaSSL, Connector/J does not enable connections with TLSv1.2 and higher by default. When connecting to servers that restrict connections to use those higher TLS versions, enable them explicitly by setting the Connector/J connection property enabledTLSProtocols (e.g., set enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2).
警告:请注意 解决方案 建议在 jre/lib/security
中编辑 jdk.tls.disabledAlgorithms
构成 安全风险 对您的应用程序和更改那里的任何内容可能会产生严重影响!
这些协议被禁用是有原因的,不应该简单地从该列表中删除所有内容,甚至只是部分内容。
注意: 如果您想从 JDK 获得更多底层见解来调试您的问题,您可以通过将以下配置传递给java 命令:
-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)
...
您可以执行以下步骤:
- 打开 java.security 文件。 (在 jre/lib/security 文件夹下)
- 找到以下行:
jdk.tls.disabledAlgorithms
- 评论完整的行。
在此之后尝试 运行 应该可以。
或者,如果您只需要特定算法,请将其从禁用列表中删除。
您可以在配置中发送它并在 java.security 文件中注释
jdbc:mysql://<host>:<port>/<dbname>?enabledTLSProtocols=TLSv1.2
我刚刚添加了 useSSL=false,它对我有用。
jdbc:mysql://<host>:<port>/<dbname>?useSSL=false
我有 JDK 8、MySQL 5.7 和 mysql-connector-java 库版本 5.1.38
这在您只想在本地环境中快速执行时很有用(不是 staging/test/prod)
我来这里是因为我遇到了同样的问题,但不幸的是,
jdbc:mysql://host:port/dbname?enabledTLSProtocols=TLSv1.2
对我不起作用,因为我使用的是 r2dbc。经过一些调试我发现参数的名称必须是 tlsVersion
而不是,所以你可以使用,例如:
spring.r2dbc.url=r2dbc:mysql://host:port/dname?tlsVersion=TLSv1.2
由于 mysql-connector-java-5.1.40-bin.jar 和 OpenJDK 1.8 版本较旧,升级到 5.1 后,我遇到了这个问题.49 版本解决了我的问题