definer会引发权限提升,因其使存储过程以定义者而非调用者身份执行;若低权限用户创建definer='root'@'%'的过程,调用时即获得root权限,可悄无声息删库、读取系统表或写文件。

为什么DEFINER会引发权限提升?
MySQL存储过程默认以DEFINER身份执行,不是调用者。如果低权限用户能创建或修改一个DEFINER = 'root'@'%'的过程,调用时就直接获得root权限——哪怕该用户自己连SELECT都没被授权。
常见错误现象不是报错,而是悄无声息地删库、读取mysql.user、写文件(通过SELECT ... INTO OUTFILE),因为执行上下文已切换。
-
DEFINER在备份恢复、主从同步中会被原样复制,高权限上下文可能被带到新环境 - MySQL不校验
DEFINER账号是否真实存在、是否拥有对应权限 - 只要用户有
CREATE ROUTINE和EXECUTE权限,就可能被利用植入恶意过程
如何安全设置SQL SECURITY?
不要依赖默认行为,显式声明安全模型才是可控的起点。
- 新建过程时强制使用:
CREATE DEFINER = CURRENT_USER SQL SECURITY INVOKER PROCEDURE p1()—— 这样过程以调用者权限运行,不会越权 - 避免写死
DEFINER = 'root'@'%';如必须指定,限定为最小必要账号,例如'proc_admin'@'localhost',且该账号仅授予过程所需的具体库表权限 - 全局禁止普通用户指定任意
DEFINER:回收SET USER类权限,确保mysql.proc表不可被非管理员直接更新
怎么检查现有高危存储过程?
线上环境很可能已经存在隐患,得主动扫描。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
执行这条语句查出所有DEFINER权限过高的过程:
SELECT name, definer, security_type FROM mysql.proc WHERE security_type = 'DEFINER';
- 重点排查
definer字段包含'root'、'%'或未限制host的项 - 对确认高危的过程,用
SHOW CREATE PROCEDURE proc_name查看定义,再用DROP PROCEDURE+ 重建方式修正SQL SECURITY INVOKER - 注意:
mysql.proc表在MySQL 8.0+中已被information_schema.ROUTINES替代,查询需适配版本
动态SQL里参数和标识符怎么防注入?
存储过程里用PREPARE拼接SQL时,数据值和语法结构必须分开处理——混在一起就是后门。
- 所有用户输入的数据值(WHERE条件、INSERT值等)必须走
?占位符:EXECUTE stmt USING @val,严禁CONCAT(..., in_name, ...) - 表名、列名、ORDER BY字段、LIMIT偏移量等标识符不能用
?,必须白名单校验:IF in_table NOT IN ('users', 'orders') THEN SIGNAL SQLSTATE '45000' ... -
USING后面只能跟用户变量(@xxx),不能直接写存储过程参数;要先SET @param = in_param;再传入 -
@xxx变量类型隐式转换容易静默失败,建议显式转换:SET @id = CAST(in_id AS UNSIGNED);
最易被忽略的是:SQL SECURITY INVOKER只解决权限问题,不解决SQL注入;而DEFINER滥用和动态SQL拼接是两条独立攻击路径,得同时堵住。










