当前位置: 首页 > news >正文

MySQL definer does not exist 问题分析

1. 问题表现

使用MySQL存储过程、函数、视图或触发器时,遇到报错

代码1  定义者不存在错误

The user specified as a definer ('someone'@'somewhere') does not exist

为简化表述,下文以存储过程指代存储过程、函数、视图和触发器等对象。

2. 解决方案

2.1. 方案1 创建用户

代码2  创建用户

CREATE USER 'someone'@'somewhere' IDENTIFIED BY 'password';

2.2. 方案1 修改存储过程定义者(需要ALTER ROUTINE和SET_USER_ID权限)

代码3  修改存储过程定义者

ALTER PROCEDURE db_name.proc_name DEFINER=`admin`@`localhost`;

2.3. 方案3 重建对象

  • 查看对象定义。

代码4  查看存储过程定义

SHOW CREATE PROCEDURE proc_name;
  • 备份。
  • 删除对象。
  • 重建对象。

3. 原因​

  • MySQL在删除用户时没有检查或删除关联对象​,导致孤儿对象产生。
  • 具有SET_USER_ID权限的用户可以将不存在的用户定义为DEFINER。

4. 原因分析

在MySQL数据库中,用户A建立的存储过程可以提供给用户B使用。用户A和B的权限可能不同,那么在执行存储过程时,使用哪个用户的权限呢?为了处理这个问题,MySQL引入了安全上下文概念。安全上下文记录了用户身份和权限信息。每个用户都有安全上下文,保存在系统表中,每个会话也有安全上下文。在建立存储过程时,可以选择执行时使用定义者或调用者的安全上下文。二者分别对应SQL SECURITY DEFINER和SQL SECURITY INVOKER选项。如果定义存储过程时没有明确指定,MySQL会使用默认选项SQL SECURITY DEFINER,用定义者安全上下文执行存储过程。对于这类存储过程,执行前首先会切换到定义者安全上下文,如果此时发现定义者不存在,MySQL就会报错。

为何会出现定义者丢失的情况呢?主要的原因是MySQL在删除用户时没有进行相关检查,导致孤儿对象的产生。另一个原因是拥有SET_USER_ID权限的用户可以将存储过程的定义者设置为不存在的用户。

各主要数据库都存在定义者、调用者等类似概念。请参考附录[示例代码]部分。

代码5  mysql-8.0.13 切换安全上下文代码 sql/auth/sql_security_ctx.cc

/**Initialize this security context from the passed in credentialsand activate it in the current thread.@param       thd@param       definer_user@param       definer_host@param       db@param[out]  backup  Save a pointer to the current security contextin the thread. In case of success it points to thesaved old context, otherwise it points to NULL.@note The Security_context_factory should be used as a replacement to thisfunction at every opportunity.During execution of a statement, multiple security contexts maybe needed:- the security context of the authenticated user, used as thedefault security context for all top-level statements- in case of a view or a stored program, possibly the securitycontext of the definer of the routine, if the object isdefined with SQL SECURITY DEFINER option.The currently "active" security context is parameterized in THDmember security_ctx. By default, after a connection isestablished, this member points at the "main" security context- the credentials of the authenticated user.Later, if we would like to execute some sub-statement or a partof a statement under credentials of a different user, e.g.definer of a procedure, we authenticate this user in a localinstance of Security_context by means of this method (andultimately by means of acl_getroot), and make thelocal instance active in the thread by re-settingthd->m_security_ctx pointer.Note, that the life cycle and memory management of the "main" andtemporary security contexts are different.For the main security context, the memory for user/host/ip isallocated on system heap, and the THD class frees this memory inits destructor. The only case when contents of the main securitycontext may change during its life time is when someone issuedCHANGE USER command.Memory management of a "temporary" security context isresponsibility of the module that creates it.@retval true  there is no user with the given credentials. The errois reported in the thread.@retval false success
*/bool Security_context::change_security_context(THD *thd,const LEX_CSTRING &definer_user,const LEX_CSTRING &definer_host,LEX_STRING *db,Security_context **backup) {bool needs_change;DBUG_ENTER("Security_context::change_security_context");DBUG_ASSERT(definer_user.str && definer_host.str);*backup = NULL;needs_change =(strcmp(definer_user.str, thd->security_context()->priv_user().str) ||my_strcasecmp(system_charset_info, definer_host.str,thd->security_context()->priv_host().str));if (needs_change) {if (acl_getroot(thd, this, const_cast<char *>(definer_user.str),const_cast<char *>(definer_host.str),const_cast<char *>(definer_host.str), db->str)) {my_error(ER_NO_SUCH_USER, MYF(0), definer_user.str, definer_host.str);DBUG_RETURN(true);}*backup = thd->security_context();thd->set_security_context(this);}DBUG_RETURN(false);
}

5. 预防措施​

  • 删除或重命名用户前检查关联对象。

6. 附录

6.1. SQL SECURITY DEFINER使用参考

应用场景

  1. 允许低权限用户执行需要高权限的操作。
  2. 限制用户只能通过预定义的接口访问数据。
  3. 所有操作都以DEFINER身份记录,便于追踪。

安全注意事项

  1. DEFINER账户应有最小必要权限。
  2. DEFINER权限过高可能导致权限提升攻击。
  3. 通常应使用特定应用账户(而非root)作为DEFINER。

管理建议

  1. 明确指定DEFINER用户。
  2. 定期审查DEFINER账户权限。
  3. 对敏感操作使用DEFINER时要格外谨慎。
  4. 考虑结合使用存储过程和视图进行细粒度访问控制。

6.2. 示例代码

代码6  openGauss

CREATE OR REPLACE PROCEDURE proc_name()
AUTHID CURRENT_USER  -- AUTHID DEFINER/SECURITY DEFINER/SECURITY INVOKER
AS $$
BEGIN-- 过程体
END;
$$;

代码7  postgreSQL

CREATE FUNCTION func_name() 
RETURNS void
SECURITY DEFINER  -- 或 SECURITY INVOKER
AS $$
BEGIN-- 函数体
END;
$$ LANGUAGE plpgsql;

代码8  SQL Server

CREATE PROCEDURE proc_name
WITH EXECUTE AS 'user_name'  -- EXECUTE AS CALLER/OWNER/SELF/'user_name'
AS
BEGIN-- 过程体
END;

代码9  SQL SECURITY INVOKER示例

CREATE PROCEDURE procedure_name()
SQL SECURITY INVOKER
BEGIN-- 过程代码
END;

代码10  SQL SECURITY INVOKER示例

CREATE PROCEDURE procedure_name()
SQL SECURITY DEFINER
BEGIN-- 存储过程代码
END;

代码11  查找按定义者查找存储过程

SELECT routine_schema, routine_name, routine_type 
FROM information_schema.routines 
WHERE definer = 'root@localhost';

代码12  检查DEFINER不存在的对象

SELECT object_type, object_schema, object_name, definer
FROM (SELECT 'PROCEDURE' AS object_type, routine_schema, routine_name, definerFROM information_schema.routinesUNIONSELECT 'VIEW', table_schema, table_name, definerFROM information_schema.viewsUNIONSELECT 'TRIGGER', trigger_schema, trigger_name, definerFROM information_schema.triggers
) all_objects
WHERE definer NOT IN (SELECT CONCAT(user,'@',host) FROM mysql.user);

7. 参考资料

https://dev.mysql.com/doc/refman/8.0/en/stored-objects-security.html#stored-objects-security-examples

http://www.lryc.cn/news/614231.html

相关文章:

  • 一动鼠标就锁屏,设备活动监控方案的技术实现与应用
  • CPO-SVM分类预测+特征贡献SHAP分析,通过特征贡献分析增强模型透明度,Matlab代码实现,引入SHAP方法打破黑箱限制,提供全局及局部双重解释视角
  • ctrl+alt+方向键导致屏幕旋转的解决方法
  • Atto Round 1 (Codeforces Round 1041, Div. 1 + Div. 2)
  • apiSQL网关调优:释放单节点的最大潜能
  • FreeRTOS---基础知识5
  • 【问题解决】使用patch-package修改node-models中的源码
  • Java 之 多态
  • CSS--后端也有自己的CSS要学
  • 腾讯 WeKnora 深度解析:大模型时代文档理解与检索的技术突破
  • Git 基础操作笔记(速查)
  • 解决:开启魔法后vscode pip命令不能安装中科大python镜像问题
  • Product Hunt 每日热榜 | 2025-08-08
  • 20250808:EasyGBS 对接大华 ICC 平台问题处理
  • 智慧农业温室大棚物联网远程监控与智能监测系统
  • 存储管理、XFS 增量备份恢复、LVM
  • 医疗设备专用电源滤波器的安全设计与应用价值|深圳维爱普
  • 【探展WAIC】从“眼见为虚”到“AI识真”:如何用大模型筑造多模态鉴伪盾牌
  • 显示器同步技术终极之战:G-Sync VS. FreeSync
  • 日本语言学校|ICA国际会话学院:从原始文本到结构化事实的建模实录(工程师向)
  • 888. 公平的糖果交换
  • 机器学习之支持向量机(原理)
  • Go 踩过的坑之协程参数不能过大
  • 四、redis入门之集群部署
  • 惯量时间常数 H 与转动惯量 J 的关系解析
  • UE5 图片9宫格切割
  • B4263 [GESP202503 四级] 荒地开垦 题解
  • Go语言实战案例:简易JSON数据返回
  • PostgreSQL技术大讲堂 - 第100讲:玩转PG数据库对象权限卷之迷宫
  • day070-Jenkins自动化与部署java、前端代码