6.2.5 访问控制,第 1 阶段:连接验证

当您尝试连接到 MySQL 服务器时,服务器根据以下条件接受或拒绝连接:

  • 您的身份以及是否可以通过提供正确的密码来验证您的身份

  • 您的帐户是锁定还是未锁定

服务器首先检查凭据,然后检查帐户锁定状态。任一步骤失败都会导致服务器完全拒绝您的访问。否则,服务器将接受连接,然后进入阶段 2 并 await 请求。

使用三个usertable 范围列(HostUserauthentication_string)执行凭据检查。锁定状态记录在usertableaccount_locked列中。仅当某些usertable 行中的HostUser列与 Client 端主机名和用户名匹配,Client 端提供该行中指定的密码且account_locked值为'N'时,服务器才接受连接。 第 6.2.4 节“指定帐户名”中给出了允许的HostUser值的规则。可以使用ALTER USER语句更改帐户锁定。

您的身份基于以下两条信息:

  • 您连接的 Client 端主机

  • 您的 MySQL 用户名

如果User列的值是非空白的,则传入 Connecting 的用户名必须完全匹配。如果User值为空白,则它与任何用户名匹配。如果与传入连接匹配的usertable 行的用户名为空,则该用户将被视为没有名称的匿名用户,而不是具有 Client 端实际指定的名称的用户。这意味着在连接持续时间内(即在第 2 阶段),将使用空白用户名进行所有进一步的访问检查。

authentication_string列可以为空白。这不是通配符,并不意味着任何密码都匹配。这意味着用户必须在未指定密码的情况下进行连接。如果服务器使用插件对 Client 端进行身份验证,则该插件实现的身份验证方法可以使用也可以不使用authentication_string列中的密码。在这种情况下,有可能还使用外部密码对 MySQL 服务器进行身份验证。

usertable 中的非空白authentication_string值 table 示加密的密码。 MySQL 不会将密码存储为明文,任何人都可以看到。而是,将尝试连接的用户提供的密码进行加密(使用由帐户身份验证插件实现的密码哈希方法)。然后在检查密码是否正确时在连接过程中使用加密的密码。这样就无需在连接上传输加密密码。参见第 6.2.1 节“帐户用户名和密码”

从 MySQL 的角度来看,加密的密码是* real *密码,因此您绝不应该允许任何人访问它。特别是,请勿授予非 Management 用户对mysql系统数据库中的 table 的读取权限

下 table 显示了usertable 中UserHost值的各种组合如何应用于传入连接。

UserHostPermissible Connections
'fred''h1.example.net'fred,从h1.example.net连接
'''h1.example.net'来自h1.example.net的任何用户
'fred''%'fred,从任何主机连接
'''%'从任何主机连接的任何用户
'fred''%.example.net'fred,从example.net域中的任何主机进行连接
'fred''x.example.%'fred,从x.example.netx.example.comx.example.edu等连接;这可能没有用
'fred''198.51.100.177'fred,从 IP 地址为198.51.100.177的主机连接
'fred''198.51.100.%'fred,从198.51.100 C 类子网中的任何主机进行连接
'fred''198.51.100.0/255.255.255.0'与前面的示例相同

传入连接的 Client 端主机名和用户名可能与usertable 中的多行匹配。前面的示例集对此进行了演示:所示的几个条目匹配了h1.example.netfred的连接。

当可能有多个匹配项时,服务器必须确定要使用哪个匹配项。它可以解决此问题,如下所示:

  • 每当服务器将usertable 读入内存时,它都会对行进行排序。

  • Client 端尝试连接时,服务器将按排序 Sequences 浏览各行。

  • 服务器使用与 Client 端主机名和用户名匹配的第一行。

服务器使用排序规则,该规则首先对最具体的Host值的行进行排序。Literals 主机名和 IP 地址是最具体的。 (LiteralsIP 地址的特异性不受其是否具有网络掩码的影响,因此198.51.100.13198.51.100.0/255.255.255.0被认为是相同的.)模式'%'table 示“任何主机”,并且是最不特定的。空字符串''也 table 示“任何主机”,但在'%'之后排序。具有相同Host值的行将按照最具体的User值进行排序(空白的User值 table 示“任何用户”,并且是最不特定的)。对于具有相同HostUser值的行,Sequences 是不确定的。

要查看其工作原理,假设usertable 如下所示:

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-

当服务器将 table 读入内存时,它将使用刚刚描述的规则对行进行排序。排序后的结果如下所示:

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-

当 Client 端尝试连接时,服务器将浏览已排序的行并使用找到的第一个匹配项。对于从localhostjeffrey的连接,table 中的两行匹配:HostUser值为'localhost'''的那一行,以及'%''jeffrey'的值的那一行。 'localhost'行首先以排序 Sequences 出现,因此这是服务器使用的行。

这是另一个例子。假设usertable 如下所示:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| h1.example.net |          | ...
+----------------+----------+-

排序的 table 如下所示:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| h1.example.net |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

第一行匹配来自h1.example.netjeffrey的连接,第二行匹配来自任何主机的jeffrey的连接。

Note

一个常见的误解是认为,对于给定的用户名,当服务器尝试查找连接的匹配项时,首先使用显式命名该用户的所有行。这不是真的。前面的示例对此进行了说明,其中来自h1.example.netjeffrey的连接首先不匹配包含'jeffrey'作为User列值的行,而是不匹配用户名的行。结果,jeffrey被认证为匿名用户,即使他在连接时指定了用户名。

如果您能够连接到服务器,但是特权不是您所期望的,则您可能已通过其他帐户的身份验证。要找出服务器用来验证您身份的帐户,请使用CURRENT_USER()功能。 (请参阅第 12.15 节“信息功能”。)它以user_name@host_name格式返回一个值,该值指示匹配的usertable 行中的UserHost值。假设jeffrey连接并发出以下查询:

mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| @localhost     |
+----------------+

此处显示的结果 table 明匹配的usertable 行具有空白User列值。换句话说,服务器将jeffrey视为匿名用户。

诊断身份验证问题的另一种方法是打印出usertable 并手动对其进行排序,以查看进行第一个匹配的位置。