第5章:数据库管理 / 5.7. MySQL访问权限系统 / 5.7.6. 访问控制, 阶段2:请求核实

一旦你建立了连接,服务器进入访问控制的阶段2。对在此连接上进来的每个请求,服务器检查你想执行什么操作,然后检查是否有足够的权限来执行它。这正是在授权表中的权限列发挥作用的地方。这些权限可以来自userdbhosttables_privcolumns_priv表。(你会发现参考5.7.2节,“权限系统工作原理”很有帮助,它列出了每个 授权表中呈现的列。)

user表在全局基础上授予赋予你的权限,该权限不管当前的数据库是什么均适用。例如,如果user表授予你DELETE权限, 你可以删除在服务器主机上从任何数据库删除行!换句话说,user表权限是超级用户权限。只把user表的权限授予超级用户如服务器或数据库主管是明智的。对其他用户,你应该把在user表中的权限设成'N'并且仅在特定数据库的基础上授权。你可以为特定的数据库、表或列授权。

dbhost表授予数据库特定的权限。在这些表中的范围列的值可以采用以下方式:

  • 通配符字符%_可用于两个表的HostDb列。它们与用LIKE操作符执行的模式匹配操作具有相同的含义。如果授权时你想使用某个字符,必须使用反斜现引用。例如,要想在数据库名中包括下划线(_),在GRANT语句中用\_来指定
  • db表的'%'Host值意味着“任何主机”,在db表中空Host值意味着“对进一步的信息咨询host表”(本节后面将描述的一个过程)。
  • host表的'%'或空Host值意味着“任何主机”。
  • 在两个表中的'%'或空Db值意味着“任何数据库”。
  • 在两个表中的空User值匹配匿名用户。

dbhost表在服务器启动时被读取并排序(同时它读user)db表在HostDbUser范围列上排序,并且host表在HostDb范围列上排序。对于user表,首先根据最具体的值最后根据最不具体的值排序,并且当服务器寻找匹配条目时,它使用它找到的第一匹配。

tables_privcolumns_priv表授予表和列特定的权限。这些表的范围列的值可以如下被指定:

  • 通配符%_可用在使用在两个表的Host列。
  • 在两个表中的'%'或空Host意味着“任何主机”。
  • 在两个表中的DbTable_nameColumn_name列不能包含通配符或空。

tables_privcolumns_priv表根据HostDbUser列被排序。这类似于db表的排序,因为只有Host列可以包含通配符,排序更简单。

请求证实进程在下面描述。(如果你熟悉访问检查的源码,你会注意到这里的描述与在代码使用的算法略有不同。描述等价于代码实际做的东西;不同处只是使解释更简单。)

对需要管理权限的请求(SHUTDOWNRELOAD等等),服务器仅检查user表条目,因为那是唯一指定管理权限的表。如果行许可请求的操作,访问被授权,否则拒绝。例如,如果你想要执行mysqladmin shutdown,但是由于user表行没有为你授予HUTDOWN权限,甚至不用检查dbhost表就拒绝你的访问。(因为它们不包含hutdown_priv行列,没有这样做的必要。)

对数据库有关的请求(INSERTUPDATE等等),服务器首先通过查找user表行来检查用户的全局(超级用户)权限。如果行允许请求的操作,访问被授权。如果在user表中全局权限不够,服务器通过检查dbhost表确定特定的用户数据库权限:

  1. 服务器在db表的HostDbUser列上查找匹配。HostUser对应连接用户的主机名和MySQL用户名。Db列对应用户想要访问的数据库。如果没有HostUser的行,访问被拒绝。
  2. 如果db表中有匹配的行而且它的Host列不是空的,该行定义用户的数据库特定的权限。
  3. 如果匹配的db表的行的Host列是空的,它表示host表列举被允许访问数据库的主机。在这种情况下,在host表中作进一步查找以发现HostDb列上的匹配。如果没有host表行匹配,访问被拒绝。如果有匹配,用户数据库特定的权限以在dbhost表的行的权限,即在两个行都是'Y'的权限的交集(而不是并集!)计算。(这样你可以授予在db表行中的一般权限,然后用host表行按主机主机为基础有选择地限制它们。)

在确定了由dbhost表行授予的数据库特定的权限后,服务器把他们加到由user表授予的全局权限中。如果结果允许请求的操作,访问被授权。否则,服务器检查在tables_privcolumns_priv表中的用户的表和列权限并把它们加到用户权限中。基于此结果允许或拒绝访问。

用布尔术语表示,前面关于用户权限如何计算的描述可以这样总结:

global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges

它可能不明显,为什么呢,如果全局user行的权限最初发现对请求的操作不够,服务器以后把这些权限加到数据库、表并列的特定权限。原因是请求可能要求超过一种类型的权限。例如,如果你执行INSERT INTO ... SELECT语句,你就需要INSERTSELECT权限。你的权限必须是user表行授予一个权限而db表行授予另一个权限。在这种情况下,你有必要的权限执行请求,但是服务器不能自己把两个表区别开来;两个行授予的权限必须组合起来。

host表不受GRANTREVOKE语句的影响,因此在大多数MySQL安装中没有使用。如果你直接修改它,你可以用于某种专门目的,例如用来维护安全服务器列表。例如,在TcXhost表包含在本地网络上所有的机器的表。这些表被授予所有的权限。

你也可以使用host表指定安全的主机。假定你有一台机器public.your.domain,它位于你认为不安全的公共区域,你可以用下列的host表条目允许除了那台机器外的网络上所有主机的访问:

+--------------------+----+-
| Host               | Db | ...
+--------------------+----+-
| public.your.domain | %  | ... (all privileges set to 'N')
| %.your.domain      | %  | ... (all privileges set to 'Y')
+--------------------+----+-

当然,一定要测试授权表中的行(例如,使用SHOW GRANTSmysqlaccess),确保你的访问权限实际按你期望的方式被设置。