应检查 host 字段非 'localhost' 且非可信内网网段(如 '192.168.%'、'10.%'、'172.16.%' 等)的用户,并结合 account_locked、password_expired 及 show grants 权限详情综合评估风险。

查出所有 Host 字段含通配符或非 localhost 的用户
MySQL 用户能否从外网访问,核心就看 Host 字段是否允许远程连接。真正有风险的是 '%'、'192.168.%'、'10.%'、'0.0.0.0' 这类值,而不是单纯看用户名。localhost 是安全边界,只要 Host 不是 'localhost' 或明确的内网 IP(如 '127.0.0.1'),就应纳入审计范围。
执行这条语句能快速筛出可疑账号:
SELECT User, Host, authentication_string, account_locked, password_expired FROM mysql.user WHERE Host != 'localhost' AND Host != '127.0.0.1' ORDER BY Host, User;
-
Host != 'localhost'和Host != '127.0.0.1'必须同时写,因为两者在 MySQL 中被视为不同账户 - 别漏掉
account_locked = 'Y'或password_expired = 'Y'的账号——它们可能被遗忘但依然存在连接面 - 如果用的是 MySQL 8.0+,
authentication_string是哈希值,不是明文,但可辅助判断是否为系统内置账号(如mysql.session)
排除已知安全的内网网段(避免误报)
直接用 != 'localhost' 会把 '192.168.10.5' 这类内网 IP 也拉进来,但实际不构成外网暴露。需要主动过滤可信网段,否则审计结果噪音太大。
推荐在 WHERE 条件中加否定匹配:
WHERE Host NOT IN ('localhost', '127.0.0.1')
AND Host NOT LIKE '192.168.%'
AND Host NOT LIKE '10.%'
AND Host NOT LIKE '172.1[6-9].%'
AND Host NOT LIKE '172.2[0-9].%'
AND Host NOT LIKE '172.3[0-1].%'
- MySQL 的
LIKE不支持正则,所以用多个NOT LIKE覆盖常见私有地址段(RFC 1918) -
'172.1[6-9].%'这种写法在 MySQL 中无效——必须拆成NOT LIKE '172.16.%'、NOT LIKE '172.17.%'等单独条件 - 如果环境用了 IPv6 或自定义网段(如
'100.64.%'),得手动补上对应NOT LIKE
结合 SHOW GRANTS 判断真实权限强度
只看 Host 只能知道“能不能连”,不能判断“连上来能干啥”。一个 'app_rw'@'%' 用户如果只有 GRANT SELECT, INSERT ON appdb.*,风险远低于 'backup'@'%' 拥有 GRANT ALL PRIVILEGES ON *.*。
批量检查时,不要逐个手敲 SHOW GRANTS FOR,而是用脚本导出关键信息:
mysql -N -s -u root -p -e "
SELECT CONCAT('SHOW GRANTS FOR ''', User, '''@''', Host, ''';')
FROM mysql.user
WHERE Host != 'localhost' AND Host != '127.0.0.1';
" | mysql -u root -p > /tmp/external_grants.sql
-
-N -s去掉列名和格式边框,确保输出是干净的 SQL 语句 - 生成的
/tmp/external_grants.sql文件里每行都是可执行的SHOW GRANTS FOR,重定向进 mysql 就能批量获取 - 重点盯
WITH GRANT OPTION和ON *.*出现的行——这两项组合意味着该账号可横向提权
注意 FLUSH PRIVILEGES 不影响 SHOW GRANTS 的实时性
有人会先 UPDATE mysql.user 再 FLUSH PRIVILEGES,然后查权限——这是误区。SHOW GRANTS 读的是内存中已加载的权限缓存,不是磁盘表。只要没用 GRANT/REVOKE 语句修改,FLUSH PRIVILEGES 对 SHOW GRANTS 输出无影响;而手动改系统表后不 FLUSH,SHOW GRANTS 也不会立即更新。
- 真正要验证权限变更是否生效,应该用目标用户重新连接后执行
SHOW GRANTS,而不是依赖管理员会话里的输出 - 审计脚本里如果混用
GRANT和后续SHOW GRANTS,中间不需要加FLUSH PRIVILEGES - 唯一需要
FLUSH PRIVILEGES的场景:你直接INSERT INTO mysql.user或UPDATE mysql.db后想让权限立刻生效
Host、SHOW GRANTS 输出、密码策略(password_expired、account_locked)三者叠在一起看——单独哪一项都可能误导判断。











