产品战略专家梁宁确认出席AICon北京站,分享AI时代下的商业逻辑与产品需求 了解详情
写点什么

MySQL 8.0 的 Public Key Retrival 错误,毫无规律可言怎么破?

  • 2021-03-24
  • 本文字数:2513 字

    阅读完需:约 8 分钟

MySQL 8.0的Public Key Retrival错误,毫无规律可言怎么破?

一、背景介绍

近期笔者所在部门在使用 MySQL 时,经常会出现如下错误,且这个错误并不会一直出现,属于某种偶发性的错误:



笔者所在部门的连接数据库的方法有 JDBC、JDBCTemplate、C3P0 连接池和 Druid 连接池等技术,在这些连接实现方法上笔者都观察到出现过上述的错误。该错误有一定的特性,就是偶尔会出现该错误,该错误并不会一直出现,该错误的出现没有明显的规律。而且笔者发现,底层使用 JDBC 连接驱动的情况下,无论上层是采用何种数据源实现技术,笔者的部门都发现会报上述错误。


针对上述错误,在笔者所在部门的软硬件环境下,笔者对 MySQL 为何会产生这个问题、这个问题产生的条件、MySQL 官方文档对这个问题的阐述、如何有效避免与解决这个问题等方面在本文进行了详细的分析与解释。希望能够帮助到真正遇到这个问题的 DBA 与开发人员。


二、环境介绍

1、实验构架

笔者所在部门使用的 MySQL 版本为 8.0.18 版本,MySQL 使用组复制技术保证高可用,即 MySQL Group Replication(MGR)。笔者复现问题以及实验的架构如下图所示:



图 2.1  实验所采用的构架


本测试使用的 MySQL MGR 集群搭建在虚拟机之上,虚拟机的详细硬件配置如下表所示:



表 2.1  详细硬件配置


为了充分测试各种类型的连接数据库的方式在笔者所在部门使用的 MySQL 上的表现,笔者分别测试 JDBC、JDBCTemplate、C3P0 以及 Druid 方式连接数据库,参与测试的软件版本如下表所示:



表 2.2  参与测试的软件版本

三、问题报错展示

在使用 JDBC 连接时,可能会出现“Public Key Retrieval is not allowed”的错误,从错误的 Java 堆栈信息中可以看出,该错误是在 JDBC 与 MySQL 建立 Connection 对象时出现的,该错误的错误堆栈如下图所示:



图 3.1  JDBC 错误堆栈


在使用 C3P0 连接池时,也会出现“Public Key Retrieval is not allowed”的错误,从错误的 Java 堆栈信息中可以看出,该错误仍是在 JDBC 与 MySQL 建立 Connection 对象时出现,该错误会导致 C3P0 连接池在初始化时失败,该错误的错误堆栈如下图所示:



图 3.2  C3P0 错误堆栈


在使用 Druid 连接池时,也会出现“Public Key Retrieval is not allowed”的错误,与 C3P0 连接池一样,会导致 Druid 连接池在初始化时失败,该错误的错误堆栈如下图所示:



图 3.3  Druid 错误堆栈

四、问题分析

笔者在查阅了网上关于“Public Key Retrieval is not allowed”错误的资料后,发现大多数网上关于该问题的博文对该问题的解释都存在一定的纰漏。首先需要明确的是出现该问题的时候,MySQL 配置的密码认证插件为如下两种:


  • sha256_password

  • caching_sha2_password


值得注意的是,如果使用“mysql_native_password”密码认证插件,不会出现“Public Key Retrieval is not allowed”错误。MySQL 配置的密码认证方式可以通过如下命令进行查看。



接着笔者来详细分析“Public Key Retrieval is not allowed”错误产生的原因。首先 MySQL 8.0 默认推荐使用“sha256_password”和“caching_sha2_password”这两种认证插件。只有较老的 MySQL 版本仍然会使用“mysql_native_password”。

根据 MySQL 提供的官方文档(https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html),这两种插件都是使用 SHA256 算法来对密码进行保护。这些插件的具体执行流程如下:


  1. 检查客户端是否禁用 SSL/TLS 加密传输;

  2. 如果客户端未禁用 SSL/TLS 加密传输,则客户端在进行认证时的认证报文(传输用户名和密码的报文)是使用 TLS 进行传输的,两种插件认为认证报文传输安全,不进行任何其他操作;

  3. 如果客户端禁用 SSL/TLS 加密传输,则客户端在进行认证时的认证报文(传输用户名和密码的报文)是使用明文进行传输的,两种插件认为认证报文传输不安全,会单独对明文报文中的密码使用 RSA 加密方式进行加密。

1、启用 SSL/TLS 加密传输的客户端认证流程

如上述流程所述,当客户端未禁用 SSL/TLS 加密传输时,通过 Wireshark 等抓包工具可以观察到整个客户端与 MySQL 服务端交互的过程都被 TLS 协议加密保护了。如下图所示:



图 4.1  启用 TLS 协议 MySQL 传输报文


虽然会产生登录的明文报文,但是该明文报文中的用户信息为空,真正的用户信息在 TLS 握手阶段后的密文中。如下图所示:



图 4.2  启用 TLS 协议 MySQL 登录数据包详情

2、禁用 SSL/TLS 加密传输的客户端认证流程

如上述流程所述,当客户端禁用 SSL/TLS 加密传输时(比如 JDBC 连接串设置 useSSL=false 参数),用户的登录信息会在明文中进行传输,如下图所示:



图 4.3  禁用 TLS 协议 MySQL 传输报文


明文传输密码存在安全问题,此时,两种插件会尝试使用 RSA 加密(RSA encryption)方法对明文报文中的密码部分进行加密,加密后的密码部分如下图所示:



图 4.4  启用 TLS 协议 MySQL 登录数据包详情

五、解决方案

根据前面的分析,导致“Public Key Retrieval is not allowed”主要是由于当禁用 SSL/TLS 协议传输后,客户端会使用服务器的公钥进行传输,默认情况下客户端不会主动去找服务器拿公钥,此时就会出现上述错误。


经过查阅官方文档,出现 Public Key Retrieval 的场景可以概括为在禁用 SSL/TLS 协议传输切当前用户在服务器端没有登录缓存的情况下,客户端没有办法拿到服务器的公钥。具体的场景如下:


  1. 新建数据库用户,首次登录;

  2. 数据库的用户名、密码发生改变后登录;

  3. 服务器端调用 FLUSH PRIVELEGES 指令刷新服务器缓存。


针对上述错误,有如下的解决方案:


  1. 在条件允许的情况下,不要禁用 SSL/TLS 协议,即不要在 CLI 客户端使用--ssl-mode=disabled,或在 JDBC 连接串中加入 useSSL=false;

  2. 如果必须禁用 SSL/TLS 协议,则可以尝试使用 CLI 客户端登录一次 MySQL 数据库制造登录缓存;

  3. 如果必须禁用 SSL/TLS 协议,则可以通过增加如下参数允许客户端获得服务器的公钥:


  • 在 JDBC 连接串中加入 allowPublicKeyRetrieval=true 参数;

  • 在 CLI 客户端连接时加入--get-server-public-key 参数;

  • 在 CLI 客户端连接时加入--server-public-key-path=file_name 参数,指定存放在本地的公钥文件。


作者介绍

农行研发中心“数风云”团队,一支朝气蓬勃、快速成长的技术团队,始终致力于农行大数据、数据库和云计算等领域的应用实践与技术创新,探索数据赋能,勇攀数据云巅,为企业数字化转型和金融科技发展不断贡献力量。


本文转载自:dbaplus 社群(ID:dbaplus)

原文链接:MySQL 8.0的Public Key Retrival错误,毫无规律可言怎么破?

2021-03-24 07:003465

评论 2 条评论

发布
用户头像
都是内网访问数据库,或者同一个VPC,同一个机房之类的,SSL不必要吧
2021-03-26 14:10
回复
用户头像
看来不用SSL,数据库登陆很危险啊。
2021-03-26 11:43
回复
没有更多了
发现更多内容

高效程序员的45个习惯:敏捷开发修炼之道(8)

石云升

敏捷开发 技术分享 轮换制

Java ConcurrentHashMap 高并发安全实现原理解析

vivo互联网技术

Java hashmap 多线程 高并发

实践解读丨Python 面向对象三大特征之多态

华为云开发者联盟

编程 面向对象

超全面分布式缓存高可用方案:哨兵机制

架构精进之路

redis哨兵模式

站在巨人的肩膀上学习:五位阿里大牛联手撰写的《深入浅出Java多线程》

Java架构之路

Java 编程 面试 并发编程 多线程

分布式数据库拆分常用之法

华为云开发者联盟

数据库 架构 分布式

java安全编码指南之:输入校验

程序那些事

java安全编码 安全编码规范 java安全编码指南

RDS、DDS和GaussDB理不清?看这一篇足够了!

华为云开发者联盟

数据库 华为云 RDS

Java开发连Redis都不会还想跳槽涨薪?先把Redis的知识点吃透再说

Java架构之路

Java redis 编程 程序员 面试

当代开发者的好帮手,浅析.NET敏捷开发框架的优势与特点

Learun

敏捷开发 开发工具

科大讯飞再握一国产核心技术,可高精细拾取30分贝超小音量

Talk A.I.

拆分链表、图解HTTPS、Zookeeper原理、如何成为技术专家、架构师三板斧 John 易筋 ARTS 打卡 Week 18

John(易筋)

ARTS 打卡计划 图解https ZooKeeper原理 架构师三板斧 拆分链表

架构设计:微服务架构如何划分?这6个标准原则让你一目了然

互联网应用架构

微服务 架构设计

收藏手册:Docker安装RabbitMQ,只需3步

互联网应用架构

Docker RabbitMQ

收藏手册:该不该用Lombok?15个常用注解全解析

互联网应用架构

lombok

第十一周.命题作业

刘璐

从linux源码看socket的阻塞和非阻塞

无毁的湖光

Linux TCP socket Linux Kenel

高难度对话读书笔记

wo是一棵草

智能商业时代的思考(三)数据驱动

刘旭东

大数据 数据驱动 智能商业

我的 2020 iOS BAT面试心得:Bigo、字节、快手、伴鱼、百度、微博等

iOSer

ios 面试

springboot2.3手册:多租户及自动创建数据,这样做

互联网应用架构

springboot mybaitsplus 多租户 自动填充基础信息

Kotlin 插件1.4.10使用报错

三爻

android kotlin

测试工程师在敏捷项目中扮演什么角色?

禅道项目管理

程序员 敏捷开发 测试

Golang 反射性能优化

余歌

性能优化 Go 语言

Java新特性:数据类型可以扔掉了?

Java 编程 架构师

JavaScript原型机制

Clloz

Java 原型

大作业2

雪涛公子

使用递增计数器的线程同步工具 —— 信号量,它的原理是什么样子的?

程序员小航

Java 源码 源码阅读 JUC Semaphore

Golang框架探索(一)

余歌

Web框架 Go web

rpc探路(一)

余歌

(0)skynet序章

休比

MySQL 8.0的Public Key Retrival错误,毫无规律可言怎么破?_编程语言_dbaplus社群_InfoQ精选文章