Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


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

8.2.12 使用部分撤销的权限限制

如果系统变量partial_revokes被启用,那么可以授予全局有效的权限。具体来说,对于拥有全局级别权限的用户,partial_revokes允许为特定的模式撤销权限,同时保留对其他模式的权限。通过这种方式实施的权限限制对于管理那些拥有全局权限但不应访问某些模式的账户非常有用。例如,可以允许一个账户修改任何表,但排除在mysql系统模式中的表。

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。请参阅第15.7.6.1节,“SET 语法用于变量赋值”

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权限,但不能对INSERT权限在world模式中的表进行操作。这意味着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通配符字符解释为字面字符,就像它们被转义为\_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`@`%`          |
+------------------------------------------------------+

如果admin授予全局的SELECT权限给u1u2,结果对每个用户都不同:

  • 如果admin授予全局的SELECT权限给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权限没有限制。授予权限只能增加给授权者的现有权限,而不能减少它们,所以如果admin授予全局的SELECT权限给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`@`%`                |
+---------------------------------------------------------+

权限限制的聚合适用于当权限被显式部分撤销(如前所述)以及当限制隐式继承自执行语句或AS user子句中指定的用户时。

如果一个帐户对某个数据库有权限限制:

  • 该帐户不能授予其他帐户在受限数据库或其中任何对象上的权限。

  • 另一个没有限制的用户执行以下语句:

    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 持有这些权限,其中 INSERTworld 模式上也被持有:

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语句的用户帐户也存在于副本中,并且它们在源服务器和副本上拥有的角色集相同。