8.4 中文镜像

MySQL 8.4 参考手册 · 中文镜像

正文为中文,英文原文默认隐藏。点击任意中文段落即可展开 / 收起对应英文原文。

打开官方英文原文 ↗

译文由机器翻译生成,仅供理解参考;有疑问请以官方英文原文为准。

MySQL 8.4 参考手册 / 27 存储对象 / 27.6 存储对象访问控制
中文点击中文段落可显示 / 隐藏英文原文本页译文覆盖 100%

27.6 存储对象访问控制27.6 Stored Object Access Control

存储程序(存储过程、函数、触发器和事件)以及视图在使用前定义,并且在被引用时在决定其权限的安全上下文中执行。存储对象执行时适用的权限由其 DEFINER 属性和 SQL SECURITY 特性控制。Stored programs (procedures, functions, triggers, and events) and views are defined prior to use and, when referenced, execute within a security context that determines their privileges. The privileges applicable to execution of a stored object are controlled by its DEFINER attribute and SQL SECURITY characteristic.

DEFINER 属性The DEFINER Attribute

存储对象定义可以包含一个 DEFINER 属性,该属性指定一个 MySQL 帐号。如果定义省略了 DEFINER 属性,则默认的对象定义者是创建它的用户。A stored object definition can include a DEFINER attribute that names a MySQL account. If a definition omits the DEFINER attribute, the default object definer is the user who creates it.

以下规则决定了您可以为存储对象指定哪些帐号作为 DEFINER 属性:The following rules determine which accounts you can specify as the DEFINER attribute for a stored object:

  • 如果您拥有 SET_ANY_DEFINER 权限,您可以将任何账户指定为 DEFINER 属性。如果该账户不存在,将生成一个警告。此外,要将存储对象的 DEFINER 属性设置为拥有 SYSTEM_USER 权限的账户,您必须拥有 SYSTEM_USER 权限。If you have the SET_ANY_DEFINER privilege, you can specify any account as the DEFINER attribute. If the account does not exist, a warning is generated. Additionally, to set a stored object DEFINER attribute to an account that has the SYSTEM_USER privilege, you must have the SYSTEM_USER privilege.

  • 否则,唯一允许的账户是您自己的账户,可以通过文字方式指定,或使用 CURRENT_USER 或 CURRENT_USER()。您不能将定义者设置为其他账户。Otherwise, the only permitted account is your own, specified either literally or as CURRENT_USER or CURRENT_USER(). You cannot set the definer to any other account.

使用不存在的 DEFINER 账户创建存储对象会创建孤立对象,这可能会产生负面影响;参见 孤立存储对象。Creating a stored object with a nonexistent DEFINER account creates an orphan object, which may have negative consequences; see Orphan Stored Objects.

SQL SECURITY 特性The SQL SECURITY Characteristic

对于存储例程(过程和函数)和视图,对象定义可以包含一个 SQL SECURITY 特性,其值可以是 DEFINER 或 INVOKER,以指定对象是在定义者上下文还是调用者上下文中执行。如果定义中省略了 SQL SECURITY 特性,默认是定义者上下文。For stored routines (procedures and functions) and views, the object definition can include an SQL SECURITY characteristic with a value of DEFINER or INVOKER to specify whether the object executes in definer or invoker context. If the definition omits the SQL SECURITY characteristic, the default is definer context.

触发器和事件没有 SQL SECURITY 特性,并且始终在定义者上下文中执行。服务器会根据需要自动调用这些对象,因此没有调用用户。Triggers and events have no SQL SECURITY characteristic and always execute in definer context. The server invokes these objects automatically as necessary, so there is no invoking user.

定义者和调用者安全上下文的区别如下:Definer and invoker security contexts differ as follows:

  • 在定义者安全上下文中执行的存储对象以其 DEFINER 属性所指定帐户的权限执行。这些权限可能与调用用户的权限完全不同。调用者必须具有适当的权限才能引用该对象(例如,调用存储过程需要 EXECUTE 权限,从视图中选择数据需要 SELECT 权限),但在对象执行期间,调用者的权限会被忽略,仅 DEFINER 帐户的权限才起作用。如果 DEFINER 帐户的权限较少,则对象能执行的操作同样受到限制。如果 DEFINER 帐户权限很高(例如管理帐户),则该对象可以执行强大的操作 无论谁调用它。A stored object that executes in definer security context executes with the privileges of the account named by its DEFINER attribute. These privileges may be entirely different from those of the invoking user. The invoker must have appropriate privileges to reference the object (for example, EXECUTE to call a stored procedure or SELECT to select from a view), but during object execution, the invoker's privileges are ignored and only the DEFINER account privileges matter. If the DEFINER account has few privileges, the object is correspondingly limited in the operations it can perform. If the DEFINER account is highly privileged (such as an administrative account), the object can perform powerful operations no matter who invokes it.

  • 在调用者安全上下文中执行的存储例程或视图只能执行调用者具有权限的操作。DEFINER 属性对对象的执行没有影响。A stored routine or view that executes in invoker security context can perform only operations for which the invoker has privileges. The DEFINER attribute has no effect on object execution.

示例Examples

考虑以下存储过程,该存储过程声明为 SQL SECURITY DEFINER,将在定义者安全上下文中执行:Consider the following stored procedure, which is declared with SQL SECURITY DEFINER to execute in definer security context:

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

任何拥有 EXECUTE 权限的用户都可以通过 CALL 语句调用 p1。然而,当 p1 执行时,它是在定义者安全上下文中执行的,因此以作为其 DEFINER 属性指定的账户 'admin'@'localhost' 的权限执行。该账户必须拥有 p1 的 EXECUTE 权限,以及对象主体中引用的表 t1 的 UPDATE 权限。否则,存储过程将会执行失败。Any user who has the EXECUTE privilege for p1 can invoke it with a CALL statement. However, when p1 executes, it does so in definer security context and thus executes with the privileges of 'admin'@'localhost', the account named as its DEFINER attribute. This account must have the EXECUTE privilege for p1 as well as the UPDATE privilege for the table t1 referenced within the object body. Otherwise, the procedure fails.

现在考虑这个存储过程,它与 p1 相同,只是其 SQL SECURITY 属性为 INVOKER:Now consider this stored procedure, which is identical to p1 except that its SQL SECURITY characteristic is INVOKER:

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

与 p1 不同,p2 在调用者安全上下文中执行,因此使用调用者的权限执行,而不管 DEFINER 属性值如何。如果调用者缺少对 p2 的 EXECUTE 权限或对表 t1 的 UPDATE 权限,p2 将执行失败。Unlike p1, p2 executes in invoker security context and thus with the privileges of the invoking user regardless of the DEFINER attribute value. p2 fails if the invoker lacks the EXECUTE privilege for p2 or the UPDATE privilege for the table t1.

孤立存储对象Orphan Stored Objects

孤立存储对象是指其 DEFINER 属性指定了一个不存在的账户的对象:An orphan stored object is one for which its DEFINER attribute names a nonexistent account:

  • 可以在创建对象时通过指定一个不存在的 DEFINER 账户来创建孤立存储对象。An orphan stored object can be created by specifying a nonexistent DEFINER account at object-creation time.

  • 已存在的存储对象可以通过执行 DROP USER 语句删除对象的 DEFINER 账户,或者通过 RENAME USER 语句重命名对象的 DEFINER 账户,从而变为孤立。An existing stored object can become orphaned through execution of a DROP USER statement that drops the object DEFINER account, or a RENAME USER statement that renames the object DEFINER account.

孤立存储对象可能会有以下问题:An orphan stored object may be problematic in these ways:

  • 由于 DEFINER 账户不存在,如果对象在定义者安全上下文中执行,可能无法按预期工作:Because the DEFINER account does not exist, the object may not work as expected if it executes in definer security context:

    • 对于存储例程,如果 SQL SECURITY 值为 DEFINER 但定义者账户不存在,则在例程执行时会发生错误。For a stored routine, an error occurs at routine execution time if the SQL SECURITY value is DEFINER but the definer account does not exist.

    • 对于触发器,在账户实际存在之前激活触发器并不是一个好主意。否则,权限检查行为将未定义。For a trigger, it is not a good idea for trigger activation to occur until the account actually does exist. Otherwise, the behavior with respect to privilege checking is undefined.

    • 对于事件,如果账户不存在,则在事件执行时会发生错误。For an event, an error occurs at event execution time if the account does not exist.

    • 对于视图,如果 SQL SECURITY 值为 DEFINER 但定义者账户不存在,则在引用视图时会发生错误。For a view, an error occurs when the view is referenced if the SQL SECURITY value is DEFINER but the definer account does not exist.

  • 如果随后为与对象无关的用途重新创建不存在的 DEFINER 帐户,则该对象可能会存在安全风险。在这种情况下,该帐户“采用”该对象,并且在具有相应权限的情况下,即使不是出于本意,也能够执行它。The object may present a security risk if the nonexistent DEFINER account is subsequently re-created for a purpose unrelated to the object. In this case, the account “adopts” the object and, with the appropriate privileges, is able to execute it even if that is not intended.

服务器实施以下帐户管理安全检查,旨在防止执行操作(可能是无意的)导致存储对象成为孤立对象,或导致目前孤立的存储对象被采用:The server imposes the following account-management security checks designed to prevent operations that (perhaps inadvertently) cause stored objects to become orphaned or that cause adoption of stored objects that are currently orphaned:

  • DROP USER 如果要删除的任何帐户被命名为任何存储对象的 DEFINER 属性,则会报错失败。(也就是说,如果删除帐户会导致存储对象成为孤立对象,则语句会失败。)DROP USER fails with an error if any account to be dropped is named as the DEFINER attribute for any stored object. (That is, the statement fails if dropping an account would cause a stored object to become orphaned.)

  • RENAME USER 如果任何要重命名的账户被指定为任何存储对象的 DEFINER 属性,则会出错。(也就是说,如果重命名账户会导致某个存储对象变成孤立对象,则语句会失败。)RENAME USER fails with an error if any account to be renamed is named as the DEFINER attribute for any stored object. (That is, the statement fails if renaming an account would cause a stored object to become orphaned.)

  • CREATE USER 如果任何要创建的账户被指定为任何存储对象的 DEFINER 属性,则会出错。(也就是说,如果创建账户会导致该账户采用当前孤立的存储对象,则语句会失败。)CREATE USER fails with an error if any account to be created is named as the DEFINER attribute for any stored object. (That is, the statement fails if creating an account would cause the account to adopt a currently orphaned stored object.)

在某些情况下,即使账号管理语句本会失败,也可能需要故意执行这些语句。为了实现这一点,如果用户拥有 ALLOW_NONEXISTENT_DEFINER 权限,该权限会覆盖孤立对象的安全检查,使语句成功执行并显示警告,而不是以错误失败。In certain situations, it may be necessary to deliberately execute those account-management statements even when they would otherwise fail. To make this possible, if a user has the ALLOW_NONEXISTENT_DEFINER privilege, that privilege overrides the orphan object security checks and the statements succeed with a warning rather than failing with an error.

要获取 MySQL 安装中用作存储对象定义者的账号信息,请查询 INFORMATION_SCHEMA。To obtain information about the accounts used as stored object definers in a MySQL installation, query the INFORMATION_SCHEMA.

此查询可识别哪些 INFORMATION_SCHEMA 表描述了具有 DEFINER 属性的对象:This query identifies which INFORMATION_SCHEMA tables describe objects that have a DEFINER attribute:

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      |
+--------------------+------------+

结果会告诉你查询哪些表以发现存在哪些存储对象的 DEFINER 值,以及哪些对象具有特定的 DEFINER 值:The result tells you which tables to query to discover which stored object DEFINER values exist and which objects have a particular DEFINER value:

  • 要确定每个表中存在哪些 DEFINER 值,请使用以下查询:To identify which DEFINER values exist in each table, use these queries:

    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;
    

    查询结果对于如下显示的任何账户都很重要:The query results are significant for any account displayed as follows:

    • 如果账户存在,则删除或重命名它会导致存储对象变成孤立对象。如果你计划删除或重命名该账户,请考虑先删除其关联的存储对象,或者将它们重新定义为具有不同的定义者。If the account exists, dropping or renaming it causes stored objects to become orphaned. If you plan to drop or rename the account, consider first dropping its associated stored objects or redefining them to have a different definer.

    • 如果账户不存在,则创建它会使其采用当前的孤立存储对象。如果你计划创建该账户,请考虑这些孤立对象是否应该与它关联。如果不需要,请将它们重新定义为具有不同的定义者。If the account does not exist, creating it causes it to adopt currently orphaned stored objects. If you plan to create the account, consider whether the orphaned objects should be associated with it. If not, redefine them to have a different definer.

    要使用不同的定义者重新定义对象,可以使用 ALTER EVENT 或 ALTER VIEW 直接修改事件和视图的 DEFINER 账户。对于存储过程、函数和触发器,必须删除该对象并重新创建以分配不同的 DEFINER 账户To redefine an object with a different definer, you can use ALTER EVENT or ALTER VIEW to directly modify the DEFINER account of events and views. For stored procedures and functions and for triggers, you must drop the object and re-create it to assign a different DEFINER account

  • 要识别具有特定 DEFINER 账户的对象,请使用这些查询,并将感兴趣的账户替换为 user_name@host_name:To identify which objects have a given DEFINER account, use these queries, substituting the account of interest for user_name@host_name:

    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';
    

    对于 ROUTINES 表,查询包括 ROUTINE_TYPE 列,以便输出行可以区分 DEFINER 是用于存储过程还是存储函数。For the ROUTINES table, the query includes the ROUTINE_TYPE column so that output rows distinguish whether the DEFINER is for a stored procedure or stored function.

    如果您正在搜索的账户不存在,那么这些查询显示的任何对象都是孤立对象。If the account you are searching for does not exist, any objects displayed by those queries are orphan objects.

风险最小化指南Risk-Minimization Guidelines

为了尽量减少存储对象创建和使用的潜在风险,请遵循以下指南:To minimize the risk potential for stored object creation and use, follow these guidelines:

  • 不要创建孤立的存储对象;也就是说,不要创建DEFINER属性指定的账户不存在的对象。不要通过删除或重命名任何现有对象的DEFINER属性所指定的账户而导致存储对象变为孤立。Do not create orphan stored objects; that is, objects for which the DEFINER attribute names a nonexistent account. Do not cause stored objects to become orphaned by dropping or renaming an account named by the DEFINER attribute of any existing object.

  • 对于存储例程或视图,如果可能,在对象定义中使用SQL SECURITY INVOKER,这样只有具有执行对象操作的适当权限的用户才能使用它。For a stored routine or view, use SQL SECURITY INVOKER in the object definition when possible so that it can be used only by users with permissions appropriate for the operations performed by the object.

  • 如果您在使用具有SET_ANY_DEFINER权限的账户创建定义者上下文存储对象时,请指定一个明确的DEFINER属性,该属性指向仅拥有执行对象所需操作权限的账户。仅在绝对必要时才指定权限很高的DEFINER账户。If you create definer-context stored objects while using an account that has the SET_ANY_DEFINER privilege, specify an explicit DEFINER attribute that names an account possessing only the privileges required for the operations performed by the object. Specify a highly privileged DEFINER account only when absolutely necessary.

  • 管理员可以通过不授予用户SET_ANY_DEFINER权限,来防止用户创建指定高权限DEFINER账户的存储对象。Administrators can prevent users from creating stored objects that specify highly privileged DEFINER accounts by not granting them the SET_ANY_DEFINER privilege.

  • 定义者上下文对象的编写应考虑到它们可能能够访问调用用户没有权限的数据。在某些情况下,您可以通过不授予未授权用户特定权限来防止引用这些对象:Definer-context objects should be written keeping in mind that they may be able to access data for which the invoking user has no privileges. In some cases, you can prevent references to these objects by not granting unauthorized users particular privileges:

    • 没有对该存储例程具有 EXECUTE 权限的用户无法引用该存储例程。A stored routine cannot be referenced by a user who does not have the EXECUTE privilege for it.

    • 没有对该视图具有适当权限的用户无法引用该视图(SELECT 权限用于从视图中选择,INSERT 权限用于向视图插入,等等)。A view cannot be referenced by a user who does not have the appropriate privilege for it (SELECT to select from it, INSERT to insert into it, and so forth).

    然而,由于触发器和事件始终在定义者上下文中执行,因此不存在这样的控制。服务器会根据需要自动调用这些对象,用户不会直接引用它们:However, no such control exists for triggers and events because they always execute in definer context. The server invokes these objects automatically as necessary, and users do not reference them directly:

    • 触发器是通过访问与其关联的表而被激活的,即使是没有特殊权限的用户的普通表访问也会触发它。A trigger is activated by access to the table with which it is associated, even ordinary table accesses by users with no special privileges.

    • 事件由服务器按计划执行。An event is executed by the server on a scheduled basis.

    在这两种情况下,如果 DEFINER 账户具有高权限,该对象可能能够执行敏感或危险的操作。即使创建对象所需的权限已从创建该对象的用户账户中撤销,这仍然成立。管理员在授予用户对象创建权限时应特别谨慎。In both cases, if the DEFINER account is highly privileged, the object may be able to perform sensitive or dangerous operations. This remains true if the privileges needed to create the object are revoked from the account of the user who created it. Administrators should be especially careful about granting users object-creation privileges.

  • 默认情况下,当执行具有 SQL SECURITY DEFINER时,MySQL 服务器不会为 DEFINER,只设置默认角色。例外情况是,如果系统变量启用了 activate_all_roles_on_login 服务器会设置所有授予 DEFINER 用户的角色,包括强制角色。因此,当CREATE PROCEDURE“或 CREATE FUNCTION 语句时,默认不会被检查。对于存储程序,如果执行角色与默认不同,程序本体可以执行 SET ROLE”来激活所需角色。此操作需谨慎,因为分配给角色的权限可能会被更改。By default, when a routine with the SQL SECURITY DEFINER characteristic is executed, MySQL Server does not set any active roles for the MySQL account named in the DEFINER clause, only the default roles. The exception is if the activate_all_roles_on_login system variable is enabled, in which case MySQL Server sets all roles granted to the DEFINER user, including mandatory roles. Any privileges granted through roles are therefore not checked by default when the CREATE PROCEDURE or CREATE FUNCTION statement is issued. For stored programs, if execution should occur with roles different from the default, the program body can execute SET ROLE to activate the required roles. This must be done with caution since the privileges assigned to roles can be changed.