23.6 存储的对象访问控制

存储的程序(过程,函数,触发器和事件)和视图是在使用前定义的,并且在引用时在确定其特权的安全上下文中执行。适用于执行存储对象的特权由其DEFINER属性和SQL SECURITY特性控制。

DEFINER 属性

存储的对象定义可以包含一个DEFINER属性,该属性命名一个 MySQL 帐户。如果定义忽略DEFINER属性,则默认对象定义者是创建它的用户。

以下规则确定可以将哪些帐户指定为存储对象的DEFINER属性:

使用不存在的DEFINER帐户创建存储的对象会创建一个孤立的对象,这可能会带来负面影响;参见孤立存储对象

SQL 安全特性

对于存储的例程(过程和函数)和视图,对象定义可以包括SQL SECURITY特性,其值是DEFINERINVOKER,以指定对象是在定义者还是调用者上下文中执行。如果定义忽略SQL SECURITYFeature,则默认为定义者上下文。

触发器和事件没有SQL SECURITYFeature,并且始终在定义程序上下文中执行。服务器根据需要自动调用这些对象,因此没有调用用户。

定义者和调用者安全上下文的区别如下:

Examples

考虑以下存储过程,该存储过程用SQL SECURITY DEFINER声明以在定义程序安全性上下文中执行:

CREATE DEFINER = 'admin'@'localhost' PROCEDURE p1()
SQL SECURITY DEFINER
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;

具有p1EXECUTE特权的任何用户都可以使用CALL语句来调用它。但是,在执行p1时,它在定义程序安全性上下文中执行,因此以'admin'@'localhost'特权(称为DEFINER属性的帐户)执行。该帐户必须具有p1EXECUTE特权以及对象主体中引用的 tablet1UPDATE特权。否则,该过程将失败。

现在考虑此存储过程,该存储过程与p1相同,除了其SQL SECURITY特性为INVOKER

CREATE DEFINER = 'admin'@'localhost' PROCEDURE p2()
SQL SECURITY INVOKER
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;

p1不同,p2在调用者安全上下文中执行,因此无论DEFINER属性值如何,都具有调用用户的特权。如果调用者缺少p2EXECUTE特权或 tablet1UPDATE特权,则p2失败。

孤立存储对象

一个孤立的存储对象是其DEFINER属性为其命名一个不存在的帐户的对象:

孤立存储的对象可能通过以下方式出现问题:

要获取有关在 MySQL 安装中用作存储对象定义程序的帐户的信息,请查询INFORMATION_SCHEMA

此查询标识哪些INFORMATION_SCHEMAtable 描述具有DEFINER属性的对象:

mysql> SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS
       WHERE COLUMN_NAME = 'DEFINER';
+--------------------+------------+
| TABLE_SCHEMA       | TABLE_NAME |
+--------------------+------------+
| information_schema | EVENTS     |
| information_schema | ROUTINES   |
| information_schema | TRIGGERS   |
| information_schema | VIEWS      |
+--------------------+------------+

结果告诉您要查询哪些 table 以发现存在哪些已存储对象DEFINER值以及哪些对象具有特定的DEFINER值:

SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.EVENTS;
SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.ROUTINES;
SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.TRIGGERS;
SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.VIEWS;

查询结果对于显示如下的任何帐户都是重要的:

要使用其他定义器重新定义对象,可以使用ALTER EVENTALTER VIEW直接修改事件和视图的DEFINER帐户。对于存储过程和函数以及触发器,必须删除对象并使用另一个DEFINER帐户重新创建该对象

SELECT EVENT_SCHEMA, EVENT_NAME FROM INFORMATION_SCHEMA.EVENTS
WHERE DEFINER = 'user_name@host_name';
SELECT ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE
FROM INFORMATION_SCHEMA.ROUTINES
WHERE DEFINER = 'user_name@host_name';
SELECT TRIGGER_SCHEMA, TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS
WHERE DEFINER = 'user_name@host_name';
SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS
WHERE DEFINER = 'user_name@host_name';

对于ROUTINEStable,查询包括ROUTINE_TYPE列,以便输出行区分DEFINER是用于存储过程还是用于存储函数。

如果您要搜索的帐户不存在,则这些查询显示的任何对象都是孤立对象。

Risk-Minimization Guidelines

为了最大程度地减少创建和使用存储对象的潜在风险,请遵循以下准则:

但是,对于触发器和事件不存在这样的控件,因为它们始终在定义器上下文中执行。服务器会根据需要自动调用这些对象,用户不会直接引用它们:

在这两种情况下,如果DEFINER帐户都具有很高的特权,则该对象可能能够执行敏感或危险的操作。如果从创建对象的用户帐户中撤消了创建对象所需的特权,这仍然适用。Management 员在授予用户对象创建特权时应格外小心。

首页