mysql 5.7及之前子查询可绕过权限检查,因解析阶段未校验嵌套访问路径权限链;应升级至8.0+、禁用derived_merge、显式设sql security definer并限制process权限。

子查询里用 SELECT ... FROM mysql.user 为什么能绕过权限检查?
MySQL 5.7 及之前版本存在一个经典漏洞:当用户拥有某个数据库的 SELECT 权限,且该库下有视图或触发器引用了系统表(如 mysql.user),攻击者可通过构造子查询间接读取敏感系统表——不是因为权限被“提升”,而是 MySQL 在子查询解析阶段未严格校验嵌套访问路径的权限链。
实操建议:
- 升级到 MySQL 8.0+,该版本默认启用
sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION并修复了多数系统表泄露路径 - 禁用非必要系统表访问:执行
REVOKE SELECT ON mysql.* FROM 'attacker'@'%';,哪怕用户只应查app_db - 避免在视图定义中硬编码
mysql.user或information_schema表,这类对象会被子查询继承上下文权限
如何关闭 subquery_cache 防止缓存污染导致的越权?
MySQL 没有叫 subquery_cache 的配置项——这是常见误解。真正影响子查询安全行为的是查询重写机制和缓存策略,但更关键的是 optimizer_switch 中的 derived_merge 和 materialization 开关。开启 materialization 会让子查询先物化成临时表,此时权限检查发生在物化前;而 derived_merge 启用时,子查询可能被合并进外层,导致权限判断逻辑错位。
实操建议:
- 检查当前开关:运行
SELECT @@optimizer_switch;,确认materialization=on且derived_merge=off - 在会话级禁用合并:执行
SET SESSION optimizer_switch='derived_merge=off';,尤其用于动态拼接 SQL 的应用后端 - 注意性能代价:关闭
derived_merge可能使某些 JOIN 查询变慢,需配合EXPLAIN验证执行计划
DEFINER 和 SQL SECURITY 怎么配才不翻车?
创建视图、存储过程或函数时若指定 DEFINER='root'@'localhost' 但没设 SQL SECURITY DEFINER,MySQL 默认按 INVOKER 执行——意味着调用者用自己的权限去查底层表,子查询就可能借道穿透。反过来,设成 DEFINER 却忘了给 DEFINER 用户授予对应系统表权限,又会导致执行时报 ERROR 1449 (HY000): The user specified as a definer ('root'@'localhost') does not exist 或静默失败。
实操建议:
- 所有生产环境视图/函数必须显式声明
SQL SECURITY DEFINER -
DEFINER账户应是专用低权限账号(如'definer_app'@'localhost'),仅授予视图所需的具体表权限,**绝不**用root或带mysql库权限的账号 - 创建后立即用普通用户测试:以无权用户身份执行
SELECT * FROM vulnerable_view;,确认返回空或权限错误,而非系统数据
为什么 SHOW PROCESSLIST 权限会放大子查询风险?
持有 PROCESS 权限的用户可看到所有连接的完整 SQL,包括那些含子查询的敏感语句。一旦应用代码里写了类似 SELECT id FROM users WHERE role IN (SELECT user FROM mysql.user),即使该语句本身因权限被拒,其原始文本仍会出现在 PROCESSLIST 中——攻击者只要能连上数据库并执行 SHOW PROCESSLIST,就能反推出系统表访问意图。
实操建议:
- 严格限制
PROCESS权限:仅 DBA 使用,应用账号一律REVOKE PROCESS ON *.* FROM 'app'@'%'; - 监控异常查询:在
slow_log或代理层(如 ProxySQL)记录含mysql.、information_schema.的 SQL 模式,触发告警 - 禁止应用拼接库名/表名:所有对元数据的访问应走预定义存储过程,且过程内做白名单校验,避免
CONCAT('SELECT * FROM ', @table_name)类逻辑
真正麻烦的不是子查询语法本身,而是权限模型与对象定义之间的耦合点——比如一个视图定义里藏着对 performance_schema 的引用,而调用者恰好有视图权限却没意识到那会激活另一层权限检查。这种隐式依赖,比明面上的 SQL 注入更难审计。











