直接查mysql.user表可定位高危账号,需同时满足host≠'localhost'、super_priv='y'或grant_priv='y'、authentication_string过短或为空三个条件,缺一不可。

直接查 mysql.user 表就能定位高危账号,但必须用对字段和条件
只看 User 和 Host 不够,真正决定风险的是三个组合条件:是否允许远程登录、是否拥有管理权限、密码是否可信。最危险的账号是 Host != 'localhost' 且 Super_priv = 'Y' 或 Grant_priv = 'Y' 的组合——这类账号等于把数据库 root 密码贴在公网门口。
CHAR_LENGTH(authentication_string) 比 <code>authentication_string = ''更可靠,能兼容 MySQL 5.7 的哈希截断行为-
plugin = 'mysql_native_password'且authentication_string = ''的账号可免密登录,password_expired = 'Y'完全拦不住 - MySQL 8.0+ 使用
caching_sha2_password时,authentication_string非空也不代表安全,需额外确认是否启用require_secure_transport
用纯 bash + mysql 命令就能完成轻量扫描,无需 Python 依赖
巡检脚本的核心难点不是写 SQL,而是安全地解析结果并避免敏感字段泄露。关键在于输出格式控制和字段分割方式。
- 用
mysql -N -s -e "SELECT ... FROM mysql.user WHERE ..."获取无头、无对齐的制表符分隔结果 - 逐行读取时必须设
IFS=$'\t',否则用户名含空格会导致字段错位(比如User被切进Host字段) - 所有过滤条件必须硬编码在 SQL 里,禁止拼接变量传入,防止 shell 注入(例如
WHERE Host = '$host'是高危写法) - 检测到
Super_priv = 'Y'且Host = '%'时,立刻echo "ALERT: wildcard root found"并exit 1,方便上层 CI/CD 中断流程
三类默认合规项必须全部返回空才表示通过
人工检查容易遗漏,建议把以下三条命令固化进每日巡检脚本。每条返回空结果才算合规,否则就是明确的安全缺口。
SELECT User, Host FROM mysql.user WHERE Host != 'localhost' AND (Super_priv = 'Y' OR Grant_priv = 'Y');SELECT User, Host FROM mysql.user WHERE CHAR_LENGTH(authentication_string)SELECT User, Host FROM mysql.user WHERE User = 'root' AND Host != 'localhost';
复杂点在于 MySQL 8.0+ 的认证插件差异和连接降级逻辑。很多脚本在云 RDS 或新版 MySQL 上失败,不是权限逻辑错了,而是连不上——比如未配置 --defaults-file 或忽略 require_secure_transport 对连接方式的强制约束。











