查mysql.user表可发现未授权账号,重点排查空用户名、host为'%'或空密码的账号;需结合SHOW GRANTS验证实际权限,检查mysql.proxies_priv和mysql.role_edges防角色与代理绕过;审计应基于元数据表而非CURRENT_USER()等运行时函数。

查 mysql.user 表就能发现未授权账号
MySQL 的账号权限全存在 mysql.user 表里,只要没被显式删除或禁用,就可能构成未授权访问风险。重点不是“有没有账号”,而是“有没有不该存在的账号”——比如空用户名、匿名用户、密码为空、或只允许本地但被意外开放远程的账号。
-
SELECT user, host, authentication_string FROM mysql.user WHERE user = '' OR host = '%' OR authentication_string = '';—— 这三类最危险:空用户名(匿名用户)、任意主机(%)、空密码 - 别漏掉
host字段细节:'user'@'192.168.%'看似可控,但如果网段暴露在公网,实际等同于开放 -
SELECT user, host FROM mysql.user WHERE account_locked = 'Y';只能说明被锁,不代表安全;有些账号虽被锁,但配置仍残留,后续误操作可能解锁
用 SHOW GRANTS 检查账号实际权限是否越界
光看 mysql.user 不够,因为权限可能通过角色、间接授权或历史残留 grant 语句堆积而来。SHOW GRANTS 才是验证某账号真实能力的唯一可靠方式。
- 对每个可疑账号执行:
SHOW GRANTS FOR 'username'@'host';—— 注意必须带完整host,否则可能查错对象 - 重点关注是否含
GRANT OPTION、ALL PRIVILEGES、或对*.*的授权;哪怕账号本身不常用,只要能转授,就是高危点 - 如果返回
ERROR 1141 (42000): There is no such grant defined for user ...,说明该账号不存在(或拼写错误),不是权限为空
检查 mysql.proxies_priv 和 mysql.role_edges 防止权限继承绕过
MySQL 5.7+ 支持角色和代理用户机制,很多审计工具只扫 mysql.user,会漏掉通过角色继承获得高权限的账号,或通过 PROXY 权限伪装成其他用户的情况。
-
SELECT * FROM mysql.proxies_priv WHERE Proxied_host != '';—— 查所有代理关系,尤其注意With_grant = 'Y'的条目 -
SELECT * FROM mysql.role_edges WHERE TO_HOST = '%';—— 查角色是否被赋予给通配 host 用户,这会让角色权限扩散失控 - 角色本身不直接登录,但一旦被授予给某个活跃账号,该账号就自动获得角色全部权限,且
SHOW GRANTS默认不展开角色内容,需加FOR ROLE显式查看
避免用 SELECT user() 或 CURRENT_USER() 做审计依据
这两个函数返回的是当前连接上下文的身份,不是系统中所有账号。拿它们当审计入口,等于只看了自己这张工牌,完全不知道办公室里还有多少没登记的人。
-
SELECT user();返回客户端声明的身份(可伪造),CURRENT_USER()返回认证后的身份(相对可靠),但二者都只反映当前会话,跟“是否存在未授权账号”无关 - 真正要审计的是元数据表,不是运行时状态;连不上数据库?那就用备份文件解析
mysql.user.MYD(MyISAM)或从ibdata1提取(InnoDB),虽然麻烦,但比依赖连接更底层 - 自动化脚本里如果混用
CURRENT_USER()判断账号是否存在,大概率漏报——它不报错,只是安静地返回一个你没想到的值
事情说清了就结束。真正难的不是查出几个账号,而是判断“这个账号到底该不该存在”——业务方说“临时用的”,DBA 说“三个月前就该删”,日志里又没留下谁建的、为什么建的。这种模糊地带,代码查不到,只能靠人对得上。


















