账户权限控制
使用部分撤销的权限限制
在MySQL 8.0.16之前,除某些模式外,无法授予全局适用的特权。从MySQL 8.0.16开始,如果partial_revokes
启用了系统变量,这是可能的。具体来说,对于在全局级别具有特权的用户,partial_revokes
可以撤消特定架构的特权,而保留其他架构的特权。如此施加的特权限制对于具有全局特权但不应被允许访问某些模式的帐户的管理可能有用。例如,可以允许一个帐户修改除mysql
系统模式中的表以外的任何表。
- 使用部分撤销
- 部分撤销对显式架构的授予
- 禁用部分撤销
- 部分撤销和复制
注意为简便起见,
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
。请参见“变量分配的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
具有全局权限SELECT
和INSERT
特权,但模式中的INSERT
表无法执行world
。即,u1
对world
表的访问是只读的。
服务器在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"]}] | +------ +------ +------------------------------------------------------ +
注意尽管可以对任何架构强加部分吊销,但是对
mysql
系统架构的特权限制尤其有用,它是防止常规帐户修改系统帐户的策略的一部分。请参阅防止系统帐户受到常规帐户的操纵。
部分撤销操作必须符合以下条件:
- 部分撤销必须按字面命名该架构。不允许包含包含
%
或_
SQL通配符的模式名称(例如myschema%
)。 - 可以使用部分吊销对不存在的模式进行限制,但前提是必须在全局范围内授予吊销的特权。如果未全局授予特权,则针对不存在的架构撤销特权会产生错误。
- 部分撤销仅适用于架构级别。您不能将部分吊销用于仅全局适用的特权(例如
FILE
或BINLOG_ADMIN
),也不能用于表,列或例程特权。
如前所述,对模式级特权的部分吊销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;
假设管理用户 dmin
具有全局但部分被撤销的SELECT
特权:
mysql>CREATE USER dmin ; mysql>GRANT SELECT ON *.*TO dmin WITH GRANT OPTION ; mysql>REVOKE SELECT ON mysql.*FROM dmin ; mysql>SHOW GRANTS FOR dmin ; +------------------------------------------------------ + | Grants for admin@% | +------------------------------------------------------ + | GRANT SELECT ON *.* TO `admin`@`%` WITH GRANT OPTION | | REVOKE SELECT ON `mysql`.* FROM `admin`@`%` | +------------------------------------------------------ +
如果 dmin
补助SELECT
全球范围内u1
和u2
,结果不同为每个用户:
如果全局
dmin
授予无特权的,则继承特权限制:SELECT
u1
SELECT
u1
dmin
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
只能添加到受让人现有的特权,而不是减少他们,所以如果dmin
授予SELECT
在全球范围内u2
,u2
不继承的dmin
限制:mysql>
GRANT SELECT ON *.*TO u2; mysql>SHOW GRANTS FOR u2; +--------------------------------- + | Grants for u2@% | +--------------------------------- + | GRANT SELECT ON *.* TO `u2`@`%` | +--------------------------------- +
如果一条GRANT
语句包含一个子句,则所应用的特权限制是该子句指定的用户/角色组合上的特权限制,而不是执行该语句的用户上的特权限制。有关该子句的信息,请参见“ GRANT语句”。AS user
AS
对授予该帐户的新特权的限制将添加到该帐户的任何现有限制中:
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 privilegeGRANT SELECT (Host ,User )ON mysql.dbTO 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
谁拥有全球几个特权,但与限制INSERT
,UPDATE
以及DELETE
:
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`@`%` | +----------------------------------------- +
撤消INSERT
将world
撤消架构级别的特权(SHOW GRANTS
不再显示架构级别的GRANT
语句):
mysql>REVOKE INSERT ON world.*FROM u1; mysql>SHOW GRANTS FOR u1; +----------------------------------------- + | Grants for u1@% | +----------------------------------------- + | GRANT SELECT, INSERT ON *.* TO `u1`@`%` | +----------------------------------------- +
撤销INSERT
上world
再次执行全局权限(的部分撤销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
在启动时禁用的尝试,服务器会记录一条错误消息并启用partial_revokes
。 - 对于尝试
partial_revokes
在运行时禁用的操作,将发生错误并且该partial_revokes
值保持不变。
要partial_revokes
在存在限制时禁用,必须首先删除限制:
确定哪些帐户有部分吊销:
SELECT User ,Host , User_attributes->>'$.Restrictions'FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';对于每个此类帐户,删除其特权限制。假设上一步显示帐户
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
部分撤销全局特权的语句对发生复制的所有主机都不会具有相同的效果,从而可能导致复制不一致或错误。
特权更改何时生效
如果mysqld服务器在没有该--skip-grant-tables
选项的情况下启动,它将在启动顺序期间将所有授权表内容读入内存。此时,内存中的表对于访问控制变得有效。
如果使用帐户管理语句间接修改授权表,则服务器会注意到这些更改并立即将授权表再次加载到内存中。“帐户管理对帐单”中介绍了帐户管理对帐单。实例包括GRANT
,REVOKE
,SET PASSWORD
,和RENAME USER
。
如果你修改授权表直接使用的语句,例如INSERT
,UPDATE
或DELETE
(不推荐),该变化对特权的效果检查,直到你要么告诉服务器重新加载表或重新启动它。因此,如果您直接更改授权表但忘记重新加载它们,则这些更改在重新启动服务器之前不会生效。这可能会让您想知道为什么更改似乎没有效果!
要告诉服务器重新加载授权表,请执行flush-privileges操作。这可以通过发出FLUSH PRIVILEGES
语句或执行mysqladmin flush-privileges或mysqladmin reload命令来完成。
授予表的重新加载会影响每个现有客户端会话的特权,如下所示:
- 表和列特权更改将在客户端的下一个请求中生效。
数据库特权更改将在客户端下次执行语句时生效。
USE db_name
注意
客户端应用程序可以缓存数据库名称;因此,如果不实际更改为其他数据库,则可能看不到这种效果。
- 全局特权和密码对于连接的客户端不受影响。这些更改仅在后续连接的会话中生效。
会话中活动角色集的更改仅对该会话立即生效。该SET ROLE
语句执行会话角色的激活和停用(请参见“ SET ROLE语句”)。
如果使用该--skip-grant-tables
选项启动服务器,则它不会读取授权表或实现任何访问控制。任何用户都可以连接并执行任何不安全的操作。为了使服务器由此开始读取表并启用访问检查,请清除特权。