您的浏览器过于古老 & 陈旧。为了更好的访问体验, 请 升级你的浏览器
一位不愿透露姓名的用户 发布于2020年07月05日 15:25 最近更新于 2020年07月05日 16:10

JDBC连接报错 MySQLNonTransientConnectionException: Public Key Retrieval is not allowed

57 次浏览 读完需要≈ 4 分钟 JDBCMySQL

我使用JDBC连接MySQL,结果却提示如下异常信息,请问该如何解决呢?

我的开发环境主要信息如下:
操作系统:Windows 7 64位;
JDK版本:1.8.0_181
MySQL版本:mysql Ver 8.0.20 for Win64 on x86_64 (MySQL Community Server - GPL)
MySQL驱动jar版本:mysql:mysql-connector-java:5.1.49
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Public Key Retrieval is not allowed
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.__newInstance(DelegatingConstructorAccessorImpl.java:45)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45009)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45012)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:403)
	at com.mysql.jdbc.Util.getInstance(Util.java:386)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:919)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:898)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:887)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:861)
	at com.mysql.jdbc.authentication.CachingSha2PasswordPlugin.nextAuthenticationStep(CachingSha2PasswordPlugin.java:130)
	at com.mysql.jdbc.MysqlIO.proceedHandshakeWithPluggableAuthentication(MysqlIO.java:1768)
	... 140 more

1 个回答

Ready · 29天前

MySQL 8 相比 MySQL 5,是一次全面的大升级,因此需要进行一些参数或设置上的调整,才能确保正常运行。

你提到的这个问题,可以参考MySQL驱动的官方文档 https://mysqlconnector.net/connection-options/#other-options,在选项AllowPublicKeyRetrieval的描述中提到如下信息:

If the user account uses sha256_password authentication, the password must be protected during transmission; TLS is the preferred mechanism for this, but if it is not available then RSA public key encryption will be used. To specify the server’s RSA public key, use the ServerRSAPublicKeyFile connection string setting, or set AllowPublicKeyRetrieval=True to allow the client to automatically request the public key from the server. Note that AllowPublicKeyRetrieval=True could allow a malicious proxy to perform a MITM attack to get the plaintext password, so it is False by default and must be explicitly enabled.

其大意是:如果你的账户使用了sha256_password 的密码验证策略,则密码必须在传输过程中被保护起来。对此默认推荐使用TLS协议,但如果TLS协议不可用,则将使用RSA公钥加密。你可以使用ServerRSAPublicKeyFile连接选项设置来指定服务器端的RSA公钥,或者你也可以设置AllowPublicKeyRetrieval=true以允许客户端自动请求服务器并下载对应的公钥。不过,需要注意,开启该设置后,将可能增加中间人攻击的风险并获取到明文密码。因此,该选项默认为false,你必须手动显示地启用它。

在看了官方文档的上述描述后,要解决该问题就不难了。

MySQL官方也警告称:sha256_password已过时,推荐使用带内存缓存(性能更好)的caching_sha2_password插件。
你可以在MySQL命令行中执行查询SHOW VARIABLES LIKE 'default_authentication_plugin'以查看实际情况。

你可以采取如下解决方案之一(仅提供思路,请自行核实):

  • 在JDBC的连接字符串中添加AllowPublicKeyRetrieval=true的参数选项【注意该方案会增加中间人攻击的风险】(一般也会同时添加useSSL=false的选项参数)。
  • 调整服务器端和客户端的设置,避免使用sha256_password插件,比如:default_authentication_plugin=mysql_native_password(这会稍微牺牲一点密码验证的安全性)。
  • 将服务器端的RSA公钥文件提前手动存储在客户端并进行相应的配置设置。

撰写答案