8.2.11 账户分类
MySQL包含了用户账户类别的概念,基于SYSTEM_USER
特权。
MySQL包含了用户账户类别的概念,系统和普通用户根据是否具有SYSTEM_USER
特权进行区分:
-
具有
SYSTEM_USER
特权的用户是系统用户。 -
没有具有
SYSTEM_USER
特权的用户是普通用户。
具有SYSTEM_USER
特权对其他特权所应用的账户有影响,以及是否受其他账户保护:
-
系统用户可以修改系统和普通账户。也就是说,具有适当特权以在普通账户上执行某个操作的用户,由于拥有
SYSTEM_USER
特权,也能够在系统账户上执行该操作。只有系统用户具有适当特权才能修改系统账户,普通用户无法修改。 -
具有适当特权以在普通账户上执行某个操作的普通用户可以修改普通账户,但不能修改系统账户。普通账户可以由系统和普通用户根据其特权进行修改。
如果一个用户具有适当特权以在普通账户上执行某个操作,SYSTEM_USER
使该用户能够在系统账户上也执行该操作。SYSTEM_USER
并不意味着其他任何特权,因此执行某个账户操作的能力仍取决于是否具有适当特权。例如,如果一个用户可以授予普通账户上SELECT
和UPDATE
特权,那么具有SYSTEM_USER
特权的用户也可以授予系统账户上SELECT
和UPDATE
特权。
系统帐户和普通帐户之间的区别使得某些帐户管理问题得到更好的控制。通过保护具有SYSTEM_USER
特权的帐户,使其不受没有该特权的帐户影响。例如,CREATE USER
特权不仅可以创建新帐户,还可以修改和删除现有帐户。如果没有系统用户概念,一名具有CREATE USER
特权的用户可以修改或删除任何已存在的帐户,包括root
帐户。系统用户概念使得限制对root
帐户(它本身是一个系统账户)的修改,只能由系统用户进行。此外,具有CREATE USER
特权的普通用户仍然可以修改或删除现有帐户,但只能是普通帐户。
SYSTEM_USER特权影响这些操作:
-
帐户管理。
帐户管理包括创建和删除帐户、授予和撤销特权、更改帐户身份验证属性(如凭据或身份验证插件)以及更改其他帐户属性(如密码过期策略)。
SYSTEM_USER特权是要求使用帐户管理语句,如
CREATE USER
和GRANT
,来操作系统帐户的必要特权。为了防止一个帐户修改系统账户,这样做,可以使其成为普通帐户,不授予它SYSTEM_USER
特权。(然而,要完全保护系统账户免受普通账户的操纵,您必须从普通账户中撤销修改特权对mysql
系统架构的权限。请参阅保护系统帐户免受普通账户操纵。) -
杀死当前会话和语句执行中的声明。
要杀死正在以
SYSTEM_USER
特权执行的会话或语句,您自己的会话必须具有SYSTEM_USER
特权,除其他必要特权(CONNECTION_ADMIN
或已弃用的SUPER
特权)外。如果将服务器设置为离线模式的用户没有
SYSTEM_USER
权限,连接到该服务器的已连接客户端用户也不会断开。然而,这些用户无法在服务器处于离线模式时启动新的连接,除非他们同时具有CONNECTION_ADMIN
或SUPER
权限。只有他们的现有连接不会终止,因为需要SYSTEM_USER
权限来执行该操作。 -
为存储对象设置
DEFINER
属性。要将存储对象的
DEFINER
属性设置为具有SYSTEM_USER
权限的帐户,您必须同时拥有SYSTEM_USER
权限以及任何其他所需权限。 -
指定强制角色。
具有
SYSTEM_USER
权限的角色不能列在mandatory_roles
系统变量的值中。 -
MySQL Enterprise Audit的审计日志过滤器中的“abort”项目的覆盖。
具有
SYSTEM_USER
权限的帐户自动分配AUDIT_ABORT_EXEMPT
权限,因此查询从该帐户执行时始终会被执行,即使审计日志过滤器中的“abort”项目将阻止它们。具有SYSTEM_USER
权限的帐户可以用于在审计配置错误后重新获得对系统的访问权。请参阅第8.4.5节,“MySQL Enterprise Audit”。
服务器内部执行的会话将被区分为系统会话或普通会话,类似于用户之间的区分:
-
具有
SYSTEM_USER
权限的会话是系统会话。 -
没有具有
SYSTEM_USER
权限的会话是普通会话。
普通会话只能执行允许给定用户执行的操作。系统会话还可以执行仅允许系统用户执行的操作。
一个会话拥有的特权是直接授予其基础帐户的特权加上当前活跃在该会话中的所有角色所授予的特权。因此,一个会话可能是一个系统会话,因为它的帐户已被直接授予了SYSTEM_USER
特权,或因为该会话激活了具有SYSTEM_USER
特权的角色。授予给一个帐户的角色,如果在会话中不活跃,则不会影响会话特权。
由于激活和停用角色可以更改会话拥有的特权,会话可能从普通会话变为系统会话或反之。若一个会话激活或停用具有SYSTEM_USER
特权的角色,该会话将立即发生适当的变化,仅限于该会话:
-
如果一个普通会话激活具有
SYSTEM_USER
特权的角色,该会话将成为系统会话。 -
如果一个系统会话停用具有
SYSTEM_USER
特权的角色,会话将变为普通会话,除非另一个具有SYSTEM_USER
特权的角色仍然活跃。
这些操作不会影响现有会话:
-
如果授予给一个帐户的
SYSTEM_USER
特权被授予或撤销,现有的会话将不会发生从普通会话到系统会话的变化。授予或撤销操作只影响后续连接该帐户的会话。 -
存储对象在会话中执行的语句使用父会话的系统或普通状态,即使对象
DEFINER
属性命名了一个系统帐户。
由于角色激活只影响会话,而不影响帐户,授予给普通帐户的具有SYSTEM_USER
特权的角色不会保护该帐户免受普通用户的攻击。角色只保护会话对应于激活角色的帐户,并且仅在会话中保护会话不被普通会话杀死。
帐户操作包括创建和删除帐户、授予和撤销特权、更改帐户身份验证属性(如凭据或身份验证插件)以及更改其他帐户属性(如密码过期策略)。
可以通过两种方式操作帐户:
-
使用帐户管理语句,如
CREATE USER
和GRANT
。这是首选方法。 -
通过直接修改表格使用语句,如
INSERT
和UPDATE
。这种方法被鼓励使用,但可能对具有适当权限的用户在包含授权表的mysql
系统架构上进行。
要完全保护系统帐户免受给定帐户的修改,请将其作为常规帐户,并不要授予它对mysql
架构的修改权限:
-
需要
SYSTEM_USER
特权来使用帐户管理语句操作系统帐户。要防止帐户通过这种方式修改系统帐户,请将其作为常规帐户,并不授予SYSTEM_USER
特权给它。此外,还应避免授予任何角色给该帐户的SYSTEM_USER
特权。 -
对
mysql
架构的特权使得通过直接修改授权表来操作系统帐户成为可能,即使修改帐户是常规帐户。要限制未经授权的直接修改系统帐户的常规帐户,可以不授予该帐户对mysql
架构的修改特权(或任何给它授予的角色)。如果常规帐户必须具有适用于所有架构的全局特权,则可以使用部分撤销来防止对mysql
架构进行修改。请参阅第8.2.12节,“使用部分撤销的特权限制”。
与不授予SYSTEM_USER
特权不同,哪怕是常规用户,也不能修改系统帐户。这种情况不会出现,因为直接授权表的修改被鼓励使用。
假设您希望创建一个名为u1
的用户,该用户具有所有架构上的全部特权,但不应能够修改系统帐户。假定partial_revokes
系统变量已启用,配置u1
如下所示:
CREATE USER u1 IDENTIFIED BY 'password';
GRANT ALL ON *.* TO u1 WITH GRANT OPTION;
-- GRANT ALL includes SYSTEM_USER, so at this point
-- u1 can manipulate system or regular accounts
REVOKE SYSTEM_USER ON *.* FROM u1;
-- Revoking SYSTEM_USER makes u1 a regular user;
-- now u1 can use account-management statements
-- to manipulate only regular accounts
REVOKE ALL ON mysql.* FROM u1;
-- This partial revoke prevents u1 from directly
-- modifying grant tables to manipulate accounts
要防止所有mysql
系统架构访问的帐户,请撤销其在mysql
架构上的全部特权,如上所示。还可以允许部分mysql
架构访问,例如只读访问。下面的例子创建一个具有全局适用于所有架构的SELECT、INSERT、UPDATE和DELETE特权,但仅对mysql
架构具有SELECT特权的帐户:
CREATE USER u2 IDENTIFIED BY 'password';
GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO u2;
REVOKE INSERT, UPDATE, DELETE ON mysql.* FROM u2;
另一个可能性是撤销所有mysql
模式权限,但授予对特定mysql
表或列的访问。这可以在部分撤销mysql
的情况下完成。以下语句使您只在u1
中读取mysql
模式,但仅限于db
表和user
表的Host
和User
列:
CREATE USER u3 IDENTIFIED BY 'password';
GRANT ALL ON *.* TO u3;
REVOKE ALL ON mysql.* FROM u3;
GRANT SELECT ON mysql.db TO u3;
GRANT SELECT(Host,User) ON mysql.user TO u3;