SQL权限审计需结合information_schema定位GRANT OPTION高危账号,区分MySQL与PostgreSQL的查询方式,规避全表扫描,识别真实敏感字段,并检查DEFINER/SECURITY DEFINER等隐式权限路径。

SQL权限审计:用information_schema查谁有GRANT OPTION
数据库里最危险的不是超级用户,而是被悄悄授予GRANT OPTION的普通账号——它能把自己没有的权限再转授出去,形成权限扩散链。直接查mysql.user或pg_roles不够,得结合权限元数据定位真实风险点。
MySQL 8.0+ 推荐用这个查询定位高危账号:
SELECT user, host, privilege_type, is_grantable FROM role_edges re JOIN role_column_grants rcg ON re.role_name = rcg.role_name WHERE is_grantable = 'YES';
PostgreSQL 则查pg_role_replication和pg_auth_members组合判断继承链中是否含admin_option为t的记录。别只看pg_roles.rolsuper,很多漏洞出在中间层角色上。
- MySQL 5.7 不支持
role_edges,得用SHOW GRANTS FOR 'user'@'host'逐个检查,脚本化时注意@通配符匹配(如'%'可能绕过白名单) - 权限视图默认只对
root或SELECT权限用户可见,审计账号必须提前授权SELECT ON information_schema.*,否则查不到任何结果 - 云数据库(如阿里云RDS、AWS RDS)常禁用
information_schema部分表,优先走控制台API拉取权限快照,而非直连查库
敏感字段识别:避开正则误杀,用column_name + data_type双条件过滤
单纯用REGEXP 'id|phone|email|card'扫字段名,会把product_id、backup_email甚至debug_flag全标成敏感项,审计报告可信度归零。真正在意的是“存储原始PII且未脱敏”的列。
先筛字段类型,再匹配语义:
SELECT table_schema, table_name, column_name, data_type, character_maximum_length
FROM information_schema.columns
WHERE data_type IN ('varchar', 'char', 'text', 'json')
AND (column_name REGEXP '^(id|phone|mobile|email|mail|card|ssn|passport|address|birth)'
OR column_name LIKE '%password%' OR column_name LIKE '%token%');-
json类型要额外检查内容结构——哪怕字段叫extra_info,也可能存着{"id_card":"110..."},需配合采样抽查 - PostgreSQL 的
citext、MySQL 的utf8mb4_bin排序规则会影响大小写匹配,REGEXP建议加i标志(如REGEXP '(?i)email') - 别忽略注释字段:
column_comment里写"身份证号(已脱敏)"比字段名更可靠,但得确认是否真脱敏——查几条实际值验证
自动化扫描:避免SELECT *触发全表扫描拖垮生产库
定期跑SELECT COUNT(*)或SELECT * FROM sensitive_table LIMIT 100看数据样例?线上库一执行就慢查询告警。审计不是取数,是探查结构与策略。
- 所有扫描操作必须加
SQL_NO_CACHE(MySQL)或SET enable_seqscan = off(PG),强制走索引或元数据缓存 - 权限检查用
SHOW GRANTS比SELECT快百倍;敏感字段识别只查information_schema.columns,绝不查业务表数据 - 云环境慎用
pt-query-digest或pg_stat_statements——它们本身会加重性能负担,建议改用数据库自带审计日志(如MySQL的general_log开关、PG的log_statement = 'ddl')
权限回收后为什么还有人能删表?检查DEFINER和SQL SECURITY
回收了user_a的DROP权限,但他写的存储过程仍能删表——问题出在函数定义者(DEFINER)和执行上下文(SQL SECURITY)。MySQL 默认SQL SECURITY DEFINER,执行时用定义者权限,不是调用者权限。
查高危存储对象:
SELECT db, name, type, definer, security_type
FROM mysql.proc
WHERE security_type = 'DEFINER' AND definer NOT IN ('root@%', 'admin@%');- PostgreSQL 没有
DEFINER概念,但SECURITY DEFINER函数同样存在风险,用pg_proc.prosecdef字段判断 - 回收权限后务必同步检查
EVENT、TRIGGER、VIEWS(尤其是WITH CHECK OPTION视图),它们都可能绕过行级权限控制 - 云数据库常禁用
DEFINER,强制INVOKER模式,此时需确认应用连接用户本身是否被过度授权
权限审计最难的不是发现谁有权限,而是确认权限在什么条件下生效、被谁继承、通过什么路径调用。一次GRANT可能影响几十个下游角色,不画依赖图,永远不知道删掉哪一行会断掉关键报表。

















