MySQL弱口令需通过哈希比对识别:导出mysql.user表authentication_string字段,按插件类型(如mysql_native_password或caching_sha2_password)用对应算法将字典口令哈希后匹配;空值、NULL及常见哈希前缀(如*2470C0C0...)属高危;8.0+因加盐需插件验证,不可仅字符串比对。

MySQL账户密码弱口令怎么快速识别
MySQL本身不提供“弱口令检测”功能,SELECT 或 SHOW USERS 都看不到明文密码,所有密码都以哈希形式存在 mysql.user 表的 authentication_string 字段里。想判断是否弱口令,必须靠外部比对——把已知弱口令字典(比如 top100、常见年份组合、默认密码)哈希后,和表中值做匹配。
- 实际操作时,先用
SELECT user, host, authentication_string FROM mysql.user导出所有账户凭证哈希 - 用工具(如
hashcat或自写脚本)对字典中的每个候选口令,按 MySQL 对应版本的加密方式生成哈希:5.7+ 默认是caching_sha2_password(SHA2-256),5.6 及以前多是mysql_native_password(SHA1 变种) - 注意:不同插件生成的哈希前缀不同,比如
$A$是caching_sha2_password,*开头是mysql_native_password,比对前得先按前缀分流处理
为什么直接查 authentication_string 不等于空就不是弱口令
空值('')或 NULL 确实代表无密码,属于典型弱口令;但非空 ≠ 安全。很多管理员会设 123456、password、root123 这类口令,哈希后长度正常、格式合法,完全骗过“非空即安全”的误判逻辑。
-
authentication_string字段为''或NULL必须立即处置 - 哈希值以
*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19这类固定字符串开头的,大概率是mysql_native_password('123456'),属于高危信号 - MySQL 8.0 启用
caching_sha2_password后,相同口令每次生成的哈希不同(带 salt),无法简单比对——必须用对应插件的验证逻辑反向校验,不能只看字符串相等
用 mysql_native_password 插件时怎么批量验证弱口令
这是最易落地的场景:老系统、PHP 应用、部分监控工具仍依赖该插件。它的哈希可逆性较强,适合脚本化扫描。
- 先确认目标账户实际使用的插件:
SELECT user, host, plugin FROM mysql.user WHERE plugin = 'mysql_native_password' - 对每个账户,取其
authentication_string值(去掉开头*),用 Python 的hashlib.sha1()计算sha1(sha1(password)),再转大写十六进制比对 - 示例(Python 片段):
import hashlib<br>pw = b'123456'<br>h1 = hashlib.sha1(pw).digest()<br>h2 = hashlib.sha1(h1).hexdigest().upper()<br># 若 h2 == '2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19',则匹配
- 别漏掉大小写混用情况,比如
Password123和password123哈希完全不同
审计时最容易被忽略的三个点
弱口令排查不是跑完脚本就完事。真正的问题常藏在权限模型、连接方式和配置残留里。
- 同一个
user@'%'账户可能被多个应用复用,改密码要同步所有调用方,否则直接中断服务 -
skip-grant-tables模式下所有认证被绕过,此时任何口令都无效——但很多人忘了它还在my.cnf里开着 - MySQL Router、ProxySQL、甚至某些备份脚本会硬编码账号密码在配置文件里,这些地方的弱口令比数据库内更难发现
事情说清了就结束。











