Mysql 访问控制1 Connection Verification

6.2.4 Access Control, Stage 1: Connection Verification


When you attempt to connect to a MySQL server, the server accepts or rejects the connection based on these conditions:    >>>>当你尝试连接某个mysql数据库时,数据库实例根据如下条件来判断是否允许你连接

  • Your identity and whether you can verify your identity by supplying the correct password    >>>>你使用的登录用户是否存在(是否能匹配mysql.user表中的某条记录),以及你的登录密码是否正确

  • Whether your account is locked or unlocked    >>>>你登录使用的用户是否处于锁定状态()

The server checks credentials first, then account locking state. A failure for either step causes the server to deny access to you completely. Otherwise, the server accepts the connection, and then enters Stage 2 and waits for requests.    >>>>mysql 先检查你的登录凭证(用户名及密码,注意mysql用户格式为 'username'@'host',包含用户名和主机两部分),然后再检查账户锁定状态。只有两步检查都通过,你才能成功登录,否则登录失败。

Credential checking is performed using the three user table scope columns (HostUser, and authentication_string). Locking state is recorded in the user table account_locked column. The server accepts the connection only if the Host and User columns in some user table row match the client host name and user name, the client supplies the password specified in that row, and the account_locked value is 'N'. The rules for permissible Host and User values are given in Section 6.2.3, “Specifying Account Names”. Account locking can be changed with the ALTER USER statement.    >>>>Mysql 根据mysql.user 系统表中的 Host,User,authentication_string值来做登录凭证检查,根据mysql.user表中的 account_locked 来检查用户的锁定状态。只有在用户的登录凭证能够与 mysql.user 表中某行的user 及host值匹配上,同时密码正确,并且登录所用账户状态为非锁定时,才能登录成功。

Your identity is based on two pieces of information:    >>>>登录mysql 的账户包括如下两部分信息

  • The client host from which you connect    >>>>客户端的ip或者主机名

  • Your MySQL user name    >>>>用户名

If the User column value is nonblank, the user name in an incoming connection must match exactly. If the User value is blank, it matches any user name. If the user table row that matches an incoming connection has a blank user name, the user is considered to be an anonymous user with no name, not a user with the name that the client actually specified. This means that a blank user name is used for all further access checking for the duration of the connection (that is, during Stage 2).    >>>>mysql.user 表中的user字段可能保存着具体的用户名,也可能为空。当user字段为非空时,用来精确匹配用户名。当user为空时,可以匹配任意用户名(可能很多人都遇到过登录的时候明明指定了某个用户名,但登录后查看当前用户确是@localhost)。如果我们匹配的时 user为空的用户,那么在检查用户权限的时候,检查的就是该user为空用户的权限,而不是你登录时指定的用户的权限,请注意。

The authentication_string column can be blank. This is not a wildcard and does not mean that any password matches. It means that the user must connect without specifying a password. If the server authenticates a client using a plugin, the authentication method that the plugin implements may or may not use the password in the authentication_string column. In this case, it is possible that an external password is also used to authenticate to the MySQL server.    >>>>mysql.user 表的 authentication_string列也可以为空,如果它为空,那么你登录时就不能指定-p参数否则报错。

Nonblank authentication_string values in the user table represent encrypted passwords. MySQL does not store passwords in cleartext form for anyone to see. Rather, the password supplied by a user who is attempting to connect is encrypted (using the password hashing method implemented by the account authentication plugin). The encrypted password then is used during the connection process when checking whether the password is correct. This is done without the encrypted password ever traveling over the connection. See Section 6.3.1, “User Names and Passwords”.    >>>>mysql.user 表中的authentication_string 字段保存的是用户的加密后的密码。mysql 不会报错明文密码。其实mysql在连接过程中使用的就是加密后的密码(即 authentication_string保存的值),因为对mysql 来说这个加密后的值才是真正的密码。

From MySQL's point of view, the encrypted password is the real password, so you should never give anyone access to it. In particular, do not give nonadministrative users read access to tables in the mysql database.    >>>>站在mysql 的角度来说 加密后的值才是真正的密码。

The following table shows how various combinations of User and Host values in the user table apply to incoming connections.    >>>>下面的表格给出了mysql.user 表中 各种可能的 User 和 Host值的组合

UserValue Host Value Permissible Connections
'fred' 'thomas.loc.gov' fred, connecting from thomas.loc.gov
'' 'thomas.loc.gov' Any user, connecting from thomas.loc.gov
'fred' '%' fred, connecting from any host
'' '%' Any user, connecting from any host
'fred' '%.loc.gov' fred, connecting from any host in the loc.gov domain
'fred' 'x.y.%' fred, connecting from x.y.netx.y.comx.y.edu, and so on; this is probably not useful
'fred' '192.168.10.177' fred, connecting from the host with IP address 192.168.10.177
'fred' '192.168.10.%' fred, connecting from any host in the 192.168.10 class C subnet
'fred' '192.168.10.0/255.255.255.0' Same as previous example

It is possible for the client host name and user name of an incoming connection to match more than one row in the user table. The preceding set of examples demonstrates this: Several of the entries shown match a connection from thomas.loc.gov by fred.    >>>>对于一个正在进行的登录来说,根据本次登录传入的 host 和user 值,可能会匹配到mysql.user 表中的多条记录。就拿上面的表格来说,从thomas.loc.gov 使用freg用户名进行登录的话,同上面表格中的第一,第二,第三,第四,第五条记录都能匹配成功。

When multiple matches are possible, the server must determine which of them to use. It resolves this issue as follows:    >>>>那么如上所说,如果某次登录能够匹配到mysql.user表中的多条记录,那么 mysql 必须选择其中的一条,mysql 通过如下方法来解决该问题:

  • Whenever the server reads the user table into memory, it sorts the rows.    >>>>当mysql 实例启动后,mysql会把user 表读入内存,并且对它进行排序(所有的权限表在实例启动时都会被读入内存中)

  • When a client attempts to connect, the server looks through the rows in sorted order.    >>>>当有连接请求时,mysql 根据mysql.user 表顺序匹配

  • The server uses the first row that matches the client host name and user name.    >>>>第一个匹配成功的行作为该次登陆的真正用户(这就是我们上面所说的,明明指定用户名,登录后确发现用户名为空的真正原因)

The server uses sorting rules that order rows with the most-specific Host values first. Literal host names and IP addresses are the most specific. (The specificity of a literal IP address is not affected by whether it has a netmask, so 192.168.1.13 and192.168.1.0/255.255.255.0 are considered equally specific.) The pattern '%' means any host and is least specific. The empty string '' also means any host but sorts after '%'. Rows with the same Host value are ordered with the most-specific User values first (a blank User value means any user and is least specific). For rows with equally-specific Host and User values, the order is indeterminate.    >>>>mysql.user在内存中的排序规则为order by host desc,user desc

To see how this works, suppose that the user table looks like this:    >>假设下面是mysql.user 表中的记录

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

When the server reads the table into memory, it sorts the rows using the rules just described. The result after sorting looks like this:    >>>>那么它在内存中排序后的顺序如下所示

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

When a client attempts to connect, the server looks through the sorted rows and uses the first match found. For a connection from localhost by jeffrey, two of the rows from the table match: the one with Host and User values of 'localhost' and '', and the one with values of '%' and 'jeffrey'. The 'localhost' row appears first in sorted order, so that is the one the server uses.    >>>>当有连接请求的时候,mysql 根据内存中mysql.user 表,顺序的进行匹配(通过user和host进行匹配,user为空的话,表示可以匹配任何用户名,host为%话表示可以匹配任何地址),取mysql.user表中第一条匹配成功的记录,作为此次的登录用户。例如从localhost 用户jeffrey进行登录,mysql.user中有两条记录能与之匹配,但是''@'localhost'这条记录排在前面,所以最终使用''@'localhost'进行登录(包括后面可能有的权限检查也都是根据''@'localhost'来进行)

Here is another example. Suppose that the user table looks like this:    >>>>下面是另外一个例子,mysql.user表中记录如下

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| thomas.loc.gov |          | ...
+----------------+----------+-

The sorted table looks like this:    >>>>mysql.user 在内存中排序后最终结果如下

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| thomas.loc.gov |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

A connection by jeffrey from thomas.loc.gov is matched by the first row, whereas a connection by jeffrey from any host is matched by the second.

Note

It is a common misconception to think that, for a given user name, all rows that explicitly name that user are used first when the server attempts to find a match for the connection. This is not true. The preceding example illustrates this, where a connection from thomas.loc.gov by jeffrey is first matched not by the row containing 'jeffrey' as the User column value, but by the row with no user name. As a result, jeffrey is authenticated as an anonymous user, even though he specified a user name when connecting.    >>>>

If you are able to connect to the server, but your privileges are not what you expect, you probably are being authenticated as some other account. To find out what account the server used to authenticate you, use the CURRENT_USER() function. (See Section 12.14, “Information Functions”.) It returns a value in user_name@host_name format that indicates the User and Host values from the matching user table row. Suppose that jeffrey connects and issues the following query:    >>>>如果你登录了数据库后发现你的权限跟你用户之前拥有的不一致,那么你可能并不是用你所指定的用户完成的登录鉴权。你可以通过 select current_user();查看你当前的登录用户。

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

The result shown here indicates that the matching user table row had a blank User column value. In other words, the server is treating jeffrey as an anonymous user.    >>>>上面的结果显示我们使用是''@'localhost'进行登录鉴权,换句话说你其实并不是用户你指定的'jeffrey'@'localhost'进行的登录鉴权

Another way to diagnose authentication problems is to print out the user table and sort it by hand to see where the first match is being made.    >>>>我们可以通过 select user,host from mysql.user order by host desc,user desc;来模拟mysql.user表在内存中的排序,然后查看我们的用户到底匹配的是mysql.user表中的哪天记录


下面通过实验来验证上面的说明(实验数据库版本是 mysql 5.6.26)

1

1)  检查目标库中用户

mysql> select user,host from mysql.user where user='haha';
Empty set (0.00 sec)

##数据库中不存在 haha 这个用户

2) 从 172.172.230.210 使用 haha 用户登录目标数据库

mysql -uhaha -p -h172.172.230.211 -P3306 -A
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 5.6.26-log MySQL Community Server (GPL)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> select current_user();
+------------------+
| current_user()   |
+------------------+
| @172.172.230.210 |
+------------------+
1 row in set (0.00 sec)

mysql> 
## 登录成功,当前用户为''@'172.172.230.210'

3)  模拟mysql.user表在内存中排序

 select user,host from mysql.user where host='172.172.230.210' order by host desc,user desc;
+-----------+-----------------+
| user      | host            |
+-----------+-----------------+
| test_shu  | 172.172.230.210 |
| test_shao | 172.172.230.210 |
| test_fei  | 172.172.230.210 |
|           | 172.172.230.210 |
+-----------+-----------------+
4 rows in set (0.00 sec)
##我们登录匹配的就是上面显示的最后一条记录(这时当前会话的权限也是继承自''@'172.172.230.210')





参考:

https://dev.mysql.com/doc/refman/5.7/en/privilege-system.html

https://dev.mysql.com/doc/refman/5.7/en/connection-access.html

https://dev.mysql.com/doc/refman/5.7/en/request-access.html


猜你喜欢

转载自blog.csdn.net/shaochenshuo/article/details/78285025