存储对象访问控制
存储的程序(过程,函数,触发器和事件)和视图是在使用前定义的,并且在引用时在确定其特权的安全上下文中执行。这些特权由其DEFINER
属性和SQL SECURITY
特征控制。
- DEFINER属性
- SQL安全特性
- 例子
- 风险最小化准则
DEFINER属性
所有存储的对象定义都可以包含一个DEFINER
名为MySQL帐户的属性。如果定义忽略该DEFINER
属性,则默认定义者是创建对象的用户。
MySQL使用以下规则来控制用户可以在对象DEFINER
属性中指定的帐户:
- 如果您具有
SET_USER_ID
或SUPER
特权,则可以将任何帐户指定为DEFINER
值,但是如果该帐户不存在,则会生成警告。另外,从MySQL 8.0.16开始,要将DEFINER
存储对象的属性设置为具有SYSTEM_USER
特权的帐户,您必须具有SYSTEM_USER
特权。 - 否则,唯一允许的帐户是您自己的帐户,可以按字面值或as
CURRENT_USER
或指定CURRENT_USER()
。您不能将定义器设置为其他帐户。
使用不存在的DEFINER
帐户创建存储的对象可能会带来负面影响:
- 对于存储的例程,如果
SQL SECURITY
值是,DEFINER
但定义者帐户不存在,则在例程执行时发生错误。 - 对于触发器,在帐户确实存在之前才进行触发器激活不是一个好主意。否则,关于特权检查的行为是不确定的。
- 对于事件,如果该帐户不存在,则会在事件执行时发生错误。
- 对于视图,如果
SQL SECURITY
值是,DEFINER
但定义者帐户不存在,则在引用该视图时会发生错误。
SQL安全特性
存储的例程(过程和函数)和视图的定义可以包括SQL SECURITY
一个值为DEFINER
或INVOKER
用于指定对象是在定义者环境还是调用者环境中执行的特征。如果定义忽略SQL SECURITY
特性,则默认为定义者上下文。
触发器和事件没有SQL SECURITY
特征,并且总是在定义器上下文中执行。服务器根据需要自动调用这些对象,因此没有调用用户。
定义者和调用者安全上下文的区别如下:
- 在定义者安全性上下文中执行的存储对象将以其
DEFINER
属性命名的帐户特权执行。这些特权可能与调用用户的特权完全不同。调用程序必须具有适当的特权才能引用该对象(例如,EXECUTE
调用存储过程或SELECT
从视图中选择),但是在对象执行期间,调用程序的特权将被忽略,只有DEFINER
帐户特权才重要。如果该DEFINER
帐户具有很少的特权,则相应地限制对象可以执行的操作。如果DEFINER
帐户具有很高的特权(例如root
帐户),无论对象是谁调用该对象都可以执行强大的操作。 - 在调用者安全上下文中执行的存储例程或视图只能执行调用者具有特权的操作。该
DEFINER
属性在对象执行期间不起作用。
例子
考虑以下存储过程,该存储过程声明SQL SECURITY DEFINER
为在定义程序安全性上下文中执行:
CREATE DEFINER = 'admin'@'localhost'PROCEDURE p1()SQL SECURITY DEFINER BEGIN UPDATE t1SET counter = counter + 1;END ;
任何具有EXECUTE
特权的用户都p1
可以使用CALL
语句来调用它。但是,在p1
执行时,它会在定义者安全性上下文中执行操作,并因此'admin'@'localhost'
以DEFINER
属性中命名的帐户的特权执行。此帐户必须具有EXECUTE
的权限p1
,以及在UPDATE
为表特权t1
的对象身体内引用。否则,该过程将失败。
现在考虑这个存储过程,p1
除了它的SQL SECURITY
特征是INVOKER
:
CREATE DEFINER = 'admin'@'localhost'PROCEDURE p2()SQL SECURITY INVOKER BEGIN UPDATE t1SET counter = counter + 1;END ;
与不同p1
,会p2
在调用者安全性上下文中执行,因此无论DEFINER
属性值如何,都具有调用用户的特权。p2
如果调用者缺少表的EXECUTE
特权p2
或UPDATE
表的特权,则失败t1
。
风险最小化准则
为了最大程度地减少创建和使用存储对象的潜在风险,请遵循以下准则:
- 对于存储的例程或视图,请
SQL SECURITY INVOKER
尽可能在对象定义中使用,以便只有具有适合于对象执行的操作权限的用户才能使用它。 - 如果在使用具有
SET_USER_ID
或SUPER
特权的帐户时创建定义者上下文存储的对象,请指定一个显式DEFINER
属性,该属性命名一个仅拥有对象执行操作所需特权的帐户。DEFINER
仅在绝对必要时指定高特权帐户。 - 管理员可以
DEFINER
通过不授予用户“SET_USER_ID
或”SUPER
特权来阻止用户创建指定高特权帐户的存储对象。 编写定义程序上下文对象时应牢记,它们可能能够访问调用用户没有权限的数据。在某些情况下,可以通过不授予未授权用户特定的特权来防止引用这些对象:
- 没有存储
EXECUTE
特权的用户不能引用该存储例程。 - 没有适当权限(
SELECT
不能从中选择,INSERT
插入等等)的用户不能引用视图。
但是,对于触发器和事件不存在这样的控件,因为它们始终在定义器上下文中执行。服务器根据需要自动调用这些对象。用户不直接引用它们:
- 触发器通过访问与其关联的表来激活,即使没有特殊特权的用户也可以通过普通表进行访问。
- 服务器按计划执行事件。
在这两种情况下,如果该
DEFINER
帐户都具有很高的特权,则该对象可能能够执行敏感或危险的操作。如果从创建对象的用户帐户中撤消了创建对象所需的特权,则情况仍然如此。管理员在授予用户对象创建特权时应格外小心。- 没有存储