MySQL 8.0 中 caching_sha2_password 认证插件的工作原理与应用
引言
自 MySQL 8.0.4 版本起,默认身份验证插件由 mysql_native_password 更改为 caching_sha2_password。这一变更同时影响了 libmysqlclient 库,使其也采用 caching_sha2_password 作为默认的身份验证机制。
认证机制的演变
传统认证方式
在 MySQL 5.6/5.7 版本中,默认使用的密码插件是 mysql_native_password。此插件的主要特点是无需加密连接即可工作,验证速度非常快。然而,其安全性存在明显缺陷,因为它使用 SHA1 算法进行密码验证。美国国家标准与技术研究院(NIST)早已建议停止使用 SHA1 算法,因为该算法与 MD5 等哈希算法一样,存在被破解的风险。
实际上,从 MySQL 5.6 开始,就引入了更为安全的认证机制: sha256_password 认证插件。该插件采用加盐密码进行多轮 SHA256 哈希(通常执行数千轮哈希运算,大大增加了暴力破解的难度)。然而,这种安全性的提升是以性能为代价的——建立安全连接和执行多轮哈希加密会消耗较多时间,导致验证速度较慢。
新认证机制的诞生
为了兼顾安全性和性能,MySQL 在 8.0.3 版本中引入了 caching_sha2_password 认证插件,作为 sha256_password 的替代方案。新插件在保留原有安全特性的基础上进行了优化,有效解决了性能问题。同时,MySQL 官方也宣布将在未来版本中移除 sha256_password 插件,建议使用该插件进行身份验证的账户迁移至 caching_sha2_password。
实际影响
由于默认身份验证机制的变更,许多用户在使用 MySQL 8.0 时遇到了连接问题。例如,使用旧版本客户端连接时可能会出现以下错误:
shell> mysql -uroot -p
ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded
尽管网络上有许多教程建议将认证方式改回 mysql_native_password,但从安全角度考虑,对于需要公网访问的 MySQL 服务,建议继续使用 caching_sha2_password 作为认证插件。
认证机制详解
mysql_native_password 工作原理
mysql_native_password 作为 MySQL 5.6/5.7 的默认密码插件,支持挑战-响应(challenge-response)机制,这是一种快速的验证方式,无需在网络中传输实际密码,也不需要加密连接。
其工作流程如下:
- 客户端连接到 MySQL 实例时,首先从服务器获取一个 20 字节的随机数(称为 nonce)
- 对于用户密码,系统通过 SHA1(SHA1(password)) 进行两次哈希计算,结果存储在
mysql.user表的authentication_string列中 - 密码哈希值未使用盐值(salt),相同密码会产生相同的哈希值
尽管这种方式在当时相对安全,但随着计算能力的提升,现在面临两种主要风险:SHA1 算法已变得容易被破解,且相同密码会产生相同哈希值,增加了彩虹表攻击的可能性。
caching_sha2_password 工作原理
caching_sha2_password 认证机制在多个方面进行了改进:
- 存储在
authentication_string中的哈希值为加盐后的值,即使用户密码相同,不同用户的哈希值也不同 - 哈希算法升级为更安全的 SHA256 算法
- 哈希计算轮数从原来的两次提升至 5000 次,增加了暴力破解的难度
- 使用 TLS 加密连接或 RSA 密钥对进行密码传输
通信过程解析
1. 快速认证模式(有缓存时)
当密码的哈希值已缓存在服务器内存中时,验证过程基于 SHA256 的挑战-响应机制,流程如下:
- 客户端发起连接请求
- 服务器生成并发送一个 20 字节的随机数据(nonce)给客户端
- 客户端使用公式 XOR(SHA256(password), SHA256(SHA256(SHA256(password)), nonce)) 生成 Scramble 并发送给服务器
- 服务器检查用户名和 SHA256(SHA256(user_password)) 是否存在于内存缓存中,若存在则验证通过
- 服务器发送 fast_auth_success 包给客户端
- 服务器发送 OK 包,进入命令阶段
2. 完整认证模式(无缓存时)
当服务器内存中没有密码哈希缓存时,caching_sha2_password 需要使用安全连接进行密码交换:
- 客户端发起连接请求
- 服务器生成并发送一个 20 字节的随机数据(nonce)给客户端
- 客户端使用公式 XOR(SHA256(password), SHA256(SHA256(SHA256(password)), nonce)) 生成 Scramble 并发送给服务器
- 服务器检查用户名和 SHA256(SHA256(user_password)) 是否存在于内存缓存中,若不存在则发送 perform_full_authentication 包
- 客户端收到 perform_full_authentication 包后,根据连接安全情况进行处理:
- 如果已建立安全连接(如 TLS),则直接发送明文密码
- 否则,请求获取服务器公钥或使用指定公钥文件,用公钥和 nonce 加密密码后发送
- 服务器使用私钥解密密码(如适用),通过 SHA256 算法计算哈希值并验证
- 验证通过后,服务器发送 OK 包,进入命令阶段
RSA 加密通信过程
在非安全连接中,caching_sha2_password 使用 RSA 非对称加密算法保护密码传输:
- 服务器生成 RSA 密钥对,并将公钥发送给客户端
- 客户端使用服务器公钥对密码进行加密
- 客户端将加密后的密码发送给服务器
- 服务器使用对应的私钥解密密码
由于只有服务器拥有私钥,即使加密数据被截获,攻击者也无法解密获取原始密码。
实施注意事项
默认身份验证插件的变更意味着在 MySQL 8.0.4 之后创建的所有新用户将默认使用 caching_sha2_password 作为身份验证插件。可以通过以下查询查看用户认证插件:
mysql> SELECT USER,PLUGIN FROM mysql.`user` ;
+------------------+-----------------------+
| USER | PLUGIN |
+------------------+-----------------------+
| root | caching_sha2_password |
| mysql.infoschema | caching_sha2_password |
| mysql.session | caching_sha2_password |
| mysql.sys | caching_sha2_password |
+------------------+-----------------------+
对于使用 caching_sha2_password 插件的客户端,连接服务器时密码传输方式取决于连接是否安全:
- 安全连接:包括使用 TLS 加密的 TCP 连接、Unix 套接字文件和共享内存连接。密码以明文格式发送,但由于连接本身是加密的,密码不会被窃听。
- 非安全连接:包括未使用 TLS 加密的 TCP 连接和命名管道连接。系统使用 RSA 密钥对对密码进行加密,防止密码被截取。服务器接收到加密密码后,使用私钥解密。加密过程中使用随机字符串,防止重放攻击。
在 MySQL 8.0.3 以上版本中,RSA 密钥对的生成和交换过程是自动完成的。
主从复制环境中的配置
MySQL 8.0.4 添加了对复制场景中 RSA 加密的支持。如果用于复制的用户使用了 caching_sha2_password 身份验证插件,且未启用安全连接,MySQL 将使用 RSA 密钥对进行密码交换。
对于传统复制,可以通过以下参数启用基于 caching_sha2_password 的 RSA 密钥交换:
# 指定 RSA 公钥路径
CHANGE MASTER TO MASTER_PUBLIC_KEY_PATH = "/path/to/public_key.pem";
# 从服务端获取 RSA 公钥
CHANGE MASTER TO GET_MASTER_PUBLIC_KEY = 1;
对于组复制(Group Replication),可以通过以下参数配置:
# 指定 RSA 公钥路径
–-group-replication-recovery-public-key-path="/path/to/public_key.pem"
# 从服务端获取 RSA 公钥
–-group-replication-recovery-get-public-key=1
数据库升级考虑
当数据库升级到 MySQL 8.0.4 或更高版本时,需要注意以下几点:
- 升级前创建的用户,其身份认证插件不会自动更改
- 升级后创建的用户默认使用
caching_sha2_password身份验证插件 - 可以通过
--default-authentication-plugin参数手动指定认证插件 - 旧版本客户端仍可连接升级前创建的用户账户
建议升级 libmysqlclient 到 MySQL 8.0.4 或更高版本,以支持新的身份验证插件。同时,出于安全考虑,建议逐步将用户账户迁移至 caching_sha2_password 认证方式。
