Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  Privilege Restriction Using Partial Revokes

8.2.12 使用部分撤销限制权限

如果启用了partial_revokes系统变量,则可以授予全局权限。如果用户在全局级别拥有权限,partial_revokes允许撤销特定模式的权限,同时保留其他模式的权限。这样可以对拥有全局权限的账户进行限制,例如,不允许账户访问某些模式的表。

Note

出于简洁起见,CREATE USER语句中不包括密码。在生产环境中,请始终分配账户密码。

使用部分撤销

系统变量partial_revokes控制是否可以对账户施加权限限制。默认情况下,partial_revokes是禁用的,尝试部分撤销全局权限将产生错误:

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT ON *.* TO u1;
mysql> REVOKE INSERT ON world.* FROM u1;
ERROR 1141 (42000): There is no such grant defined for user 'u1' on host '%'

要允许REVOKE操作,请启用partial_revokes

SET PERSIST partial_revokes = ON;

SET PERSIST设置当前MySQL实例的值,并将其保存,以便在后续服务器重启时生效。要更改当前MySQL实例的值而不影响后续重启,请使用GLOBAL关键字而不是PERSIST。请参阅Section 15.7.6.1,“SET Syntax for Variable Assignment”

启用partial_revokes后,部分撤销操作将成功:

mysql> REVOKE INSERT ON world.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+------------------------------------------+
| Grants for u1@%                          |
+------------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%`  |
| REVOKE INSERT ON `world`.* FROM `u1`@`%` |
+------------------------------------------+

SHOW GRANTS将部分撤销列出为REVOKE语句在其输出中。结果表明,u1拥有全局SELECTINSERT权限,但不能在world模式下的表上执行INSERT操作。也就是说,u1world表的访问是只读的。

服务器在mysql.user系统表中记录了通过部分撤销实施的权限限制。如果账户有部分撤销,其User_attributes列值将具有Restrictions属性:

mysql> SELECT User, Host, User_attributes->>'$.Restrictions'
       FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';
+------+------+------------------------------------------------------+
| User | Host | User_attributes->>'$.Restrictions'                   |
+------+------+------------------------------------------------------+
| u1   | %    | [{"Database": "world", "Privileges": ["INSERT"]}] |
+------+------+------------------------------------------------------+
Note

虽然可以对任何模式实施部分撤销,但对mysql系统模式的权限限制尤其有用,可以作为防止常规账户修改系统账户的一部分策略。请参阅保护系统账户免受常规账户的操作

部分撤销操作受以下条件限制:

  • 可以使用部分撤销对不存在的模式实施限制,但只有在撤销的权限是全局授予的。如果撤销的权限不是全局授予的,撤销不存在的模式将产生错误。

  • 部分撤销仅适用于架构级别。您不能使用部分撤销来撤销仅在全局范围内适用的权限(例如FILEBINLOG_ADMIN),或用于表、列或例程权限。

  • 在权限分配中,启用partial_revokes会导致 MySQL 将模式名称中的未转义的 _% SQL 通配符字符解释为文字字符,就像它们已经被转义为 \_\% 一样。由于这改变了 MySQL 解释权限的方式,因此在可能启用 partial_revokes 的安装中,可能需要避免在权限分配中使用未转义的通配符。

如前所述,架构级别权限的部分撤销在 SHOW GRANTS 输出中显示为 REVOKE 语句。这与 SHOW GRANTS 表示“普通”架构级别权限的方式不同:

  • 授予架构级别权限时,它们在输出中以自己的 GRANT 语句表示:

    mysql> CREATE USER u1;
    mysql> GRANT UPDATE ON mysql.* TO u1;
    mysql> GRANT DELETE ON world.* TO u1;
    mysql> SHOW GRANTS FOR u1;
    +---------------------------------------+
    | Grants for u1@%                       |
    +---------------------------------------+
    | GRANT USAGE ON *.* TO `u1`@`%`        |
    | GRANT UPDATE ON `mysql`.* TO `u1`@`%` |
    | GRANT DELETE ON `world`.* TO `u1`@`%` |
    +---------------------------------------+
  • 撤销架构级别权限时,它们从输出中消失,不会显示为 REVOKE 语句:

    mysql> REVOKE UPDATE ON mysql.* FROM u1;
    mysql> REVOKE DELETE ON world.* FROM u1;
    mysql> SHOW GRANTS FOR u1;
    +--------------------------------+
    | Grants for u1@%                |
    +--------------------------------+
    | GRANT USAGE ON *.* TO `u1`@`%` |
    +--------------------------------+

当用户授予权限时,授予者对该权限的任何限制都会被继承到被授予者,除非被授予者已经拥有该权限且没有限制。考虑以下两个用户,其中一个拥有全局 SELECT 权限:

CREATE USER u1, u2;
GRANT SELECT ON *.* TO u2;

假设管理用户 admin 拥有全局但部分撤销的 SELECT 权限:

mysql> CREATE USER admin;
mysql> GRANT SELECT ON *.* TO admin WITH GRANT OPTION;
mysql> REVOKE SELECT ON mysql.* FROM admin;
mysql> SHOW GRANTS FOR admin;
+------------------------------------------------------+
| Grants for admin@%                                   |
+------------------------------------------------------+
| GRANT SELECT ON *.* TO `admin`@`%` WITH GRANT OPTION |
| REVOKE SELECT ON `mysql`.* FROM `admin`@`%`          |
+------------------------------------------------------+

如果 adminSELECT 全局授予 u1u2,结果对每个用户都不同:

  • 如果 adminSELECT 全局授予 u1,谁从未拥有 SELECT 权限,u1 将继承 admin 权限限制:

    mysql> GRANT SELECT ON *.* TO u1;
    mysql> SHOW GRANTS FOR u1;
    +------------------------------------------+
    | Grants for u1@%                          |
    +------------------------------------------+
    | GRANT SELECT ON *.* TO `u1`@`%`          |
    | REVOKE SELECT ON `mysql`.* FROM `u1`@`%` |
    +------------------------------------------+
  • 另一方面,u2 已经拥有全局 SELECT 权限且没有限制。GRANT 只能添加到被授予者的现有权限中,而不能减少它们,因此如果 adminSELECT 全局授予 u2u2 不会继承 admin 限制:

    mysql> GRANT SELECT ON *.* TO u2;
    mysql> SHOW GRANTS FOR u2;
    +---------------------------------+
    | Grants for u2@%                 |
    +---------------------------------+
    | GRANT SELECT ON *.* TO `u2`@`%` |
    +---------------------------------+

如果 GRANT 语句包括一个 AS user 子句,那么应用的权限限制将是该子句指定的用户/角色组合,而不是执行语句的用户。有关 AS 子句的信息,请参阅 第 15.7.1.6 节,“GRANT 语句”

授予新权限时,添加到账户的权限限制:

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO u1;
mysql> REVOKE INSERT ON mysql.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@%                                         |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE INSERT ON `mysql`.* FROM `u1`@`%`                |
+---------------------------------------------------------+
mysql> REVOKE DELETE, UPDATE ON db2.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@%                                         |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE UPDATE, DELETE ON `db2`.* FROM `u1`@`%`          |
| REVOKE INSERT ON `mysql`.* FROM `u1`@`%`                |
+---------------------------------------------------------+

权限限制的聚合适用于明确撤销和隐式继承的情况。

如果账户在某个架构上有权限限制:

  • 该账户不能授予其他账户该架构或其内部对象的权限。

  • 另一个没有限制的账户可以授予被限制的账户该架构或其内部对象的权限。假设一个无限制的用户执行以下语句:

    CREATE USER u1;
    GRANT SELECT, INSERT, UPDATE ON *.* TO u1;
    REVOKE SELECT, INSERT, UPDATE ON mysql.* FROM u1;
    GRANT SELECT ON mysql.user TO u1;          -- grant table privilege
    GRANT SELECT(Host,User) ON mysql.db TO u1; -- grant column privileges

    结果账户拥有这些权限,可以在受限架构中执行有限操作:

    mysql> SHOW GRANTS FOR u1;
    +-----------------------------------------------------------+
    | Grants for u1@%                                           |
    +-----------------------------------------------------------+
    | GRANT SELECT, INSERT, UPDATE ON *.* TO `u1`@`%`           |
    | REVOKE SELECT, INSERT, UPDATE ON `mysql`.* FROM `u1`@`%`  |
    | GRANT SELECT (`Host`, `User`) ON `mysql`.`db` TO `u1`@`%` |
    | GRANT SELECT ON `mysql`.`user` TO `u1`@`%`                |
    +-----------------------------------------------------------+

如果账户在全局权限上有限制,该限制将被以下任何操作删除:

  • 授予账户全局权限,而该账户没有该权限的限制。

  • 在模式级别授予权限。

  • 撤销全局权限。

考虑用户 u1,该用户在全局范围内持有多个权限,但在 INSERTUPDATEDELETE 上有限制:

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO u1;
mysql> REVOKE INSERT, UPDATE, DELETE ON mysql.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+----------------------------------------------------------+
| Grants for u1@%                                          |
+----------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%`  |
| REVOKE INSERT, UPDATE, DELETE ON `mysql`.* FROM `u1`@`%` |
+----------------------------------------------------------+

从没有限制的账户授予全局权限给 u1,将删除权限限制。例如,要删除 INSERT 限制:

mysql> GRANT INSERT ON *.* TO u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@%                                         |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE UPDATE, DELETE ON `mysql`.* FROM `u1`@`%`        |
+---------------------------------------------------------+

在模式级别授予权限给 u1,将删除权限限制。例如,要删除 UPDATE 限制:

mysql> GRANT UPDATE ON mysql.* TO u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@%                                         |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE DELETE ON `mysql`.* FROM `u1`@`%`                |
+---------------------------------------------------------+

撤销全局权限将删除权限,包括任何限制。例如,要删除 DELETE 限制(以删除所有 DELETE 访问权为代价):

mysql> REVOKE DELETE ON *.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+-------------------------------------------------+
| Grants for u1@%                                 |
+-------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE ON *.* TO `u1`@`%` |
+-------------------------------------------------+

如果账户在全局和模式级别都有权限,必须在模式级别撤销两次以实现部分撤销。假设 u1 拥有这些权限,其中 INSERT 既在全局范围内也在 world 模式下:

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT ON *.* TO u1;
mysql> GRANT INSERT ON world.* TO u1;
mysql> SHOW GRANTS FOR u1;
+-----------------------------------------+
| Grants for u1@%                         |
+-----------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%` |
| GRANT INSERT ON `world`.* TO `u1`@`%`   |
+-----------------------------------------+

撤销 INSERTworld 上撤销模式级别权限 (SHOW GRANTS 不再显示模式级别 GRANT 语句):

mysql> REVOKE INSERT ON world.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+-----------------------------------------+
| Grants for u1@%                         |
+-----------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%` |
+-----------------------------------------+

撤销 INSERTworld 上再次执行部分撤销全局权限 (SHOW GRANTS 现在包括模式级别 REVOKE 语句):

mysql> REVOKE INSERT ON world.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+------------------------------------------+
| Grants for u1@%                          |
+------------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%`  |
| REVOKE INSERT ON `world`.* FROM `u1`@`%` |
+------------------------------------------+

部分撤销与模式授予

为提供账户对某些模式的访问权限,而不是其他模式,部分撤销提供了与明确授予模式级别访问权限的替代方法。两种方法都有不同的优缺点。

授予模式级别权限,而不是全局权限:

  • 添加新模式:该模式默认情况下对现有账户不可访问。对于任何应该访问该模式的账户,DBA 必须授予模式级别访问权限。

  • 添加新账户:DBA 必须授予每个该账户应该访问的模式的模式级别访问权限。

授予全局权限,并使用部分撤销:

  • 添加新模式:该模式对现有账户默认情况下可访问。对于任何不应该访问该模式的账户,DBA 必须添加部分撤销。

  • 添加新账户:DBA 必须授予全局权限,及每个受限模式的部分撤销。

使用明确授予模式级别权限的方法对于账户来说更方便,访问权限仅限于少数模式。使用部分撤销的方法对于账户来说更方便,访问权限涵盖所有模式,除了少数例外。

禁用部分撤销

一旦启用,partial_revokes 不能禁用,如果任何账户有权限限制。 如果存在这样的账户,禁用 partial_revokes 将失败:

要禁用partial_revokes时存在限制,首先必须删除限制:

  1. 确定哪些账户具有部分撤销权限:

    SELECT User, Host, User_attributes->>'$.Restrictions'
    FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';
  2. 对于每个这样的账户,删除其权限限制。假设前一步骤显示账户u1具有这些限制:

    [{"Database": "world", "Privileges": ["INSERT", "DELETE"]

    可以通过多种方式删除限制:

    • 在全局范围内授予权限,不受限制:

      GRANT INSERT, DELETE ON *.* TO u1;
    • 在模式级别授予权限:

      GRANT INSERT, DELETE ON world.* TO u1;
    • 撤销全局权限(假设它们不再需要):

      REVOKE INSERT, DELETE ON *.* FROM u1;
    • 删除账户本身(假设它不再需要):

      DROP USER u1;

删除所有权限限制后,可以禁用部分撤销:

SET PERSIST partial_revokes = OFF;

部分撤销和复制

在复制场景中,如果partial_revokes在任何主机上启用,则必须在所有主机上启用。否则,REVOKE语句以部分撤销全局权限对所有主机的影响不同,可能导致复制不一致或错误。

partial_revokes启用时,二进制日志中将记录GRANT语句的扩展语法,包括当前用户和其当前活动角色。如果在复制目标服务器上不存在记录的用户或角色,复制应用程序线程将在GRANT语句处停止并出现错误。确保所有在复制源服务器上发出或可能发出GRANT语句的用户账户也存在于复制目标服务器上,并且具有与源服务器相同的角色集。