訪問權限控制系統|全方位認識 mysql 系統庫

1、訪問權限控制系統概述

什麼是訪問權限控制系統?

  • MySQL的mysql 系統庫提供了user、db、tables_priv、columns_priv、procs_priv、proxies_priv幾張表用於存放不同權限範圍的用戶帳號相關的數據,這些表共同組成了MySQL 的訪問權限系統。

  • MySQL權限系統的主要功能是對從給定主機連接到MySQL Server的用戶進行身份驗證,並校驗該用戶在該Server中的數據庫對象訪問的權限(如SELECT,INSERT,UPDATE和DELETE),另外,還包括管理匿名用戶訪問和授予特定的MySQL權限的功能(如執行 LOAD DATA INFILE 語句和管理操作權限等)。

MySQL訪問權限系統的用戶界面由幾個SQL語句組成:如CREATE USER、GRANT和REVOKE。

在Server內部,MySQL 將權限信息存儲在mysql數據庫的權限表中。MySQL Server在啓動時將這些表的內容讀入內存,後續針對用戶的訪問控制決策基於權限表的內存副本實現。

MySQL訪問權限系統可以確保只有被允許的(與用戶權限匹配的)操作才能夠在Server中執行。當一個用戶連接到MySQL Server時,用戶的認證身份由"請求連接的主機名和用戶名"確定,MySQL使用主機名+用戶名的方式來識別和區分"相同主機不同用戶"和"不同主機相同用戶"發出的請求(例如:從office.example.com連接的用戶joe和從home.example.com連接的用戶joe在MySQL Server中實際上是被當作兩個不同的連接者來處理的,所以可以設置不同的密碼、不同的權限),例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@localhost : mysql 01:03:04> show grants for test_a@'localhost';
+---------------------------------------------+
| Grants for test_a@localhost                 |
+---------------------------------------------+
GRANT SELECT ON *.* TO 'test_a'@'localhost' |
+---------------------------------------------+
1 row in set (0.00 sec)
root@localhost : mysql 01:03:22> show grants for test_a@'%';
+---------------------------------------------+
| Grants for test_a@%                         |
+---------------------------------------------+
GRANT SELECTINSERT ON *.* TO 'test_a'@'%' |
+---------------------------------------------+
1 row in set (0.00 sec)

當用戶使用客戶端程序連接到MySQL Server時,MySQL的訪問控制分爲如下兩個階段:

  • 階段1:Server根據身份標識(主機名+用戶名組成的帳號名)在MySQL 的訪問權限控制表中查詢相關信息,以確定需要接受或拒絕該用戶的連接(沒有查詢到就拒絕連接),如果查詢到了用戶記錄,則校驗用戶提供的帳號密碼是否正確,如果密碼不正確則拒絕連接,這一階段報錯信息類似爲:ERROR 1045 (28000): Access denied for user 'test_a'@'localhost' (using password: YES)

  • 階段2:用戶連接成功之後,Server會檢查用戶訪問請求中的每個聲明來確定是否有足夠的權限來執行。例如:如果嘗試從數據庫的表中查詢數據行或從數據庫中刪除表,Server將驗證該用戶否具有該表的SELECT權限或數據庫的DROP權限,如果無對應權限,則這一階段的報錯信息類似爲:ERROR 1142 (42000) at line 1: UPDATE command denied to user 'test_a'@'localhost' for table 'sbtest1'

如果某用戶在已經建立連接期間,權限發生了變更(自身修改或者其他用戶修改),那麼對於該用戶執行下一條語句時,這些權限變更不一定會立即生效。如果未生效需要執行flush privileges;

2、MySQL 提供了哪些權限

MySQL 提供的權限列表如下(其中,all或者all privileges代表瞭如下列表中除了grant option權限之外的所有權限):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
root@localhost : (none) 11:55:05> show privileges;
+-------------------------+--------------------------------------- 
+-------------------------------------------------------+
| Privilege               | Context                               |     Comment                                               |
+-------------------------+---------------------------------------    +-------------------------------------------------------+
Alter                   | Tables                                |     To alter the table                                    |
Alter routine           | Functions,Procedures                  |     To alter or drop stored functions/procedures          |
Create                  | Databases,Tables,Indexes              |     To create new databases and tables                    |
Create routine          | Databases                             |     To use CREATE FUNCTION/PROCEDURE                      |
Create temporary tables | Databases                             |     To use CREATE TEMPORARY TABLE                         |
Create view             | Tables                                |     To create new views                                   |
Create user             | Server Admin                          |     To create new users                                   |
Delete                  | Tables                                |     To delete existing rows                               |
Drop                    | Databases,Tables                      |     To drop databases, tables, and views                  |
| Event                   | Server Admin                          |     To createalterdrop and execute events             |
Execute                 | Functions,Procedures                  |     To execute stored routines                            |
| File                    | File access on server                 |     To read and write files on the server                 |
Grant option            | Databases,Tables,Functions,Procedures |     To give to other users those privileges you possess   |
Index                   | Tables                                |     To create or drop indexes                             |
Insert                  | Tables                                |     To insert data into tables                            |
| Lock tables             | Databases                             |     To use LOCK TABLES (together with SELECT privilege)   |
| Process                 | Server Admin                          |     To view the plain text of currently executing queries |
| Proxy                   | Server Admin                          |     To make proxy user possible                           |
References              | Databases,Tables                      |     To have references on tables                          |
| Reload                  | Server Admin                          |     To reload or refresh tables, logs and privileges      |
| Replication client      | Server Admin                          |     To ask where the slave or master servers are          |
| Replication slave       | Server Admin                          |     To read binary log events from the master             |
Select                  | Tables                                |     To retrieve rows from table                           |
| Show databases          | Server Admin                          |     To see all databases with SHOW DATABASES              |
| Show view               | Tables                                |     To see views with SHOW CREATE VIEW                    |
| Shutdown                | Server Admin                          |     To shut down the server                               |
| Super                   | Server Admin                          |     To use KILL thread, SET GLOBAL, CHANGE MASTER, etc.   |
Trigger                 | Tables                                |     To use triggers                                       |
Create tablespace       | Server Admin                          |     To create/alter/drop tablespaces                      |
Update                  | Tables                                |     To update existing rows                               |
| Usage                   | Server Admin                          |     No privileges - allow connect only                    |
+-------------------------+---------------------------------------    +-------------------------------------------------------+
31 rows in set (0.00 sec)

以上權限列表中,Context字段顯示了該權限的一個使用環境(或者說是權限的作用域),根據Context的不同,分爲如下三類:

  • 管理權限:用於管理MySQL Server的操作。這些權限是全局性的,不能授予給特定的數據庫或數據庫對象(只能使用 方式授予) 。

    * Create user  
    * Event  
    * Process  
    * Proxy  
    * Reload  
    * Replication client  
    * Replication slave  
    * Show databases  
    * Shutdown  
    * Super  
    * Create tablespace  
    * Usage  
    * Grant option 

  • 數據庫級別權限:用於授予某數據庫及其數據庫中的所有對象的權限。這些權限可以被授予特定的數據庫,也可以授予所有數據庫(可以使用 ,代表全局對象,也可以使用db.*,代表某庫下的所有對象) 。

    * Create  
    * Create routine  
    * Create temporary tables  
    * Drop  
    * Lock tables  
    * References

  • 數據庫對象級別權限: 可爲數據庫中的特定對象、數據庫內給定類型的對象授予權限,也可以授予所有數據庫( ,代表全局對象,db.*代表某庫下的所有對象,db.tb代表某庫下某對象) 。 

    * Alter  
    * Alter routine  
    * Create view  
    * Delete  
    * Execute  
    * File  
    * Index  
    * Insert  
    * Select  
    * Show view  
    * Trigger  
    * Update

通常,按照我們使用經驗還可以按照如下方式劃分。

  • 開發權限

    * DELETE  
    * INSERT  
    * SELECT  
    * UPDATE  
    * ALTER  
    * CREATE TEMPORARY TABLES  
    * TRIGGER  
    * CREATE VIEW  
    * SHOW VIEW  
    * ALTER ROUTINE  
    * CREATE ROUTINE  
    * EXECUTE  
    * INDEX  
    * EVENT

  • 管理權限-表級別(這裏把帶表級別的管理命令都歸類爲表級別)  
    * CREATE  
    * FILE  
    * DROP  
    * LOCK TABLES

  • 管理權限-server級別  
    * GRANT OPTION  
    * CREATE TABLESPACE  
    * CREATE USER  
    * PROCESS  
    * PROXY  
    * RELOAD  
    * REPLICATION CLIENT  
    * REPLICATION SLAVE  
    * SHOW DATABASES  
    * SHUTDOWN  
    * SUPER  
    * USAGE  
    * ALL [PRIVILEGES]

下面,我們挨個解釋每個權限的作用。

  • ALL或ALL PRIVILEGES:除了grant option之外,其他所有權限的簡寫方式

  • ALTER:該權限用於使用ALTER TABLE語句來更改表的結構(ALTER TABLE語句除了該權限之外還需要CREATE和INSERT權限。ALTER TABLE RENAME語句需要舊錶上的ALTER和DROP權限,新表上的CREATE和INSERT權限)。

  • ALTER ROUTINE:該權限用於修改或刪除存儲過程或存儲函數。

  • CREATE:該權限用於創建庫和表。

  • CREATE ROUTINE:該權限用於創建存儲過程或函數。

  • CREATE TABLESPACE:該權限用於創建、修改、刪除表空間文件和日誌組文件。

  • CREATE TEMPORARY TABLES:該權限用於創建臨時表,使用CREATE TEMPORARY TABLE語句創建臨時表,一旦某會話創建臨時表成功後,Server不會在該表上執行進一步的權限檢查。即,創建該臨時表的會話可以該臨時表執行任何操作,例如:DROP TABLE、INSERT、UPDATE、SELECT等操作。

  • CREATE USER:該權限用於使用ALTER USER、CREATE USER、DROP USER、RENAME USER、REVOKE ALL PRIVILEGES語句。

  • CREATE VIEW:該權限用於使用CREATE VIEW語句。

  • DELETE:該權限用於從數據庫表中刪除數據記錄。

  • DROP:該權限用戶刪除現有庫、或表、或視圖等對象。另外,如果在分區表上使用ALTER TABLE ... DROP PARTITION語句,必須要有表的DROP權限,要執行TRUNCATE TABLE也需要DROP權限(但要注意,如果將MySQL數據庫的DROP權限授予給用戶,則該用戶可以刪除存儲MySQL訪問權記錄的數據庫mysql)。

  • EVENT:該選項用於創建、更改、刪除或查看Event Scheduler事件。

  • EXECUTE:該權限用於執行存儲過過程或函數。

  • FILE:該權限用於執行LOAD DATA INFILE和SELECT ... INTO OUTFILE語句以及LOAD_FILE()函數來讀取和寫入Server主機上的文件。具有FILE權限的用戶可以讀取Server主機上任何可讀或MySQL Server可讀的文件。(即,用戶可讀取datadir目錄中的任何文件),FILE權限還使用戶能夠在MySQL Server有寫入權限的任何目錄下創建新文件。所以,作爲安全保護措施,Server不會覆蓋現有文件(即執行導出數據到文本時,如果文件名重疊則導出語句無法成執行)。在MySQL 5.7版本中,可以使用secure_file_priv系統變量限制FILE權限的讀寫目錄。

  • GRANT OPTION:該權限用於授予或回收其他用戶或自己擁有的權限。

  • INDEX:該權限用於創建或刪除索引。INDEX權限適用於在已存在的表上使用CREATE INDEX語句,如果用戶具有CREATE權限,則可以在CREATE TABLE語句中包含索引定義語句。

  • INSERT:該權限用於向表中插入數據記錄行。對於ANALYZE TABLE、OPTIMIZE TABLE和REPAIR TABLE表維護語句也需要INSERT權限。

  • LOCK TABLES:該權限用於LOCK TABLES語句對錶顯式加鎖,持有表鎖的用戶對該表有讀寫權限,未持有表鎖的用戶對錶的讀寫訪問會被阻塞。

  • PROCESS:該權限用於顯示有關在Server內執行的線程信息(即關於會話正在執行的語句相關狀態信息)。擁有該權限的用戶在使用SHOW PROCESSLIST語句或mysqladmin processlist命令查看有關線程信息時除了自己的線程信息之外還可以查看到屬於其他帳號的線程信息。另外,使用SHOW ENGINE語句以及查看information_schema 數據字典庫中的相當一部分表也需要該權限。

  • PROXY:該權限使用戶能夠模仿另一個用戶。

  • REFERENCES:該權限在創建外鍵約束時,需要用戶具有父表的REFERENCES權限。

  • RELOAD:該權限允許用戶使用FLUSH語句。擁有該權限的用戶還可以使用與FLUSH操作等效的mysqladmin子命令:flush-hosts,flush-logs,flush-privileges,flush-status,flush-tables,flush-threads,refresh和reload 
    * mysqladmin的reload子命令會通知Server將權限表重新加載到內存中。flush-privileges作用與reload子命令作用相同。refresh子命令會通知Server關閉並重新打開日誌文件並刷新所有表。類似地,其他flush-xxx子命令也會執行類似於刷新的功能,這些子命令刷新的對象更具體,例如:只想刷新日誌文件則使用flush-logs子命令。

  • REPLICATION CLIENT:該權限用於使用SHOW MASTER STATUS、SHOW SLAVE STATUS和SHOW BINARY LOGS語句。

  • REPLICATION SLAVE:該權限用於從庫服務器連接到主庫服務器並請求主庫binlog 日誌。如果沒有此權限,從庫將無法請求主庫數據庫變更的binlog日誌。

  • SELECT:該權限用於從數據庫表中查詢數據行記錄。SELECT語句只有在它們實際從表中檢索行記錄時才需要SELECT權限。但某些SELECT語句不需要訪問表,並且可以在沒有任何數據庫權限的情況下執行。例如,使用SELECT語句拼接的常量表達式:SELECT 1 + 1; SELECT PI()* 2;  
    * 另外,當使用UPDATE或DELETE語句時使用where子句指定了某列的條件值時,也需要該列的SELECT權限。否則,你會發現可以update不帶where子句更新全表,卻不能使用where語句指定更新某些行記錄 。 
    * 對基表或視圖使用EXPLAIN語句也需要用戶對錶或視圖具有該權限。

  • SHOW DATABASES:該權限用於執行SHOW DATABASE語句,若沒有此權限的帳戶,則只能看到他們具有對應訪問權限的數據庫列表,如果Server使用了--skip-show-database選項啓動,則沒有該權限的用戶即使對某庫有其他訪問權限也不能使用SHOW DATABASES語句查看任何數據庫列表(會報:ERROR 1227 (42000): Access denied; you need (at least one of) the SHOW DATABASES privilege(s) for this operation)

  • SHOW VIEW:該權限用於執行SHOW CREATE VIEW語句。對視圖使用EXPLAIN語句也需要此權限。

  • SHUTDOWN:該權限用於執行SHUTDOWN語句、mysqladmin shutdown命令和mysql_shutdown() C API函數。

  • SUPER:該權限用於如下這些操作和Server行爲:  
    * 修改全局系統配置變量需要此權限。對於某些系統變量,修改會話級別的系統配置變量也需要SUPER權限(如果修改會話級別的系統配置變量值需要SUPER權限的,在變量的解釋文檔中會進行說明,例如:binlog_format、sql_log_bin和sql_log_off)  
    * 對全局事務特徵的更改(start transaction語句) 。 
    * 從庫服務器用於執行啓動和停止複製的語句,包括組複製 。 
    * 從庫服務器用於執行使用CHANGE MASTER TO和CHANGE REPLICATION FILTER語句 。 
    * 執行PURGE BINARY LOGS和BINLOG語句 。 
    * 如果視圖或存儲程序定義了DEFINER屬性,則擁有SUPER權限的用戶就算不是該視圖或存儲程序的創建者,仍然可以執行該視圖或存儲程序 。 
    * 執行CREATE SERVER、ALTER SERVER和DROP SERVER語句 。 
    * 執行mysqladmin debug命令 。 
    * 用於InnoDB key自旋 。 
    * 用於執行通過DES_ENCRYPT()函數啓用讀取DES密鑰文件 。 
    * 用於執行用戶自定義函數時啓用版本令牌 。 
    * 對於超過了最大連接數之後具有SUPER的帳戶還可以的操作 。 
    * 1)、使用KILL語句或mysqladmin kill命令來終止屬於其他帳戶的線程。(注意:無論是否擁有SUPER權限,用戶總是可以kill自己的線程)  
    * 2)、即使Server總連接數達到max_connections系統變量定義的值,Server 也會接受來自具有SUPER權限的用戶一個額外的連接 。 
    * 3)、即使Server啓用了read_only系統變量,具有SUPER權限的用戶仍然可以執行數據更新。另外,還有帳戶管理語句GRANT和REVOKE等 。 
    * 4)、SUPER客戶端連接Server時,Server不執行init_connect系統變量指定的內容 。 
    * 5)、處於脫機模式(已啓用offline_mode系統變量)的Server不會中斷具有SUPER權限用戶的連接,且仍然接收具有SUPER權限用戶的新連接請求 。 
    * 如果啓用了二進制日誌記錄功能,則用戶可能還需要SUPER權限才能創建或更改存儲的功能。

  • TRIGGER:該權限用於觸發器的操作。您必須擁有某表的該權限才能針對該表創建、刪除、執行或查看該表的觸發器。

  • UPDATE:該權限用於執行對數據庫表中的數據行更新操作。

  • USAGE:該權限代表用戶“無任何權限”。全局級別權限,擁有該權限的用戶可以登錄到數據庫Server中,但默認配置下除了能夠執行部分show命令之外,其他任何數據變更和數據庫查詢的操作都無法執行。

  • 向用戶只授予用戶需要的權限,不要授予額外的多餘的,特別是管理權限,如下:  
    * FILE:該權限用於將任何文件讀入數據庫表中,MySQL Server可以在Server主機上讀取任何文件。包括Server數據目錄中所有可讀文件。然後可以使用SELECT訪問該導入數據的表,將其讀取表中的內容返回給客戶端 。 
    * GRANT OPTION:該權限用於執行將權限授予其他用戶 。 
    * ALTER:該權限用於修改表定義,重命名錶等操作 。 
    * SHUTDOWN:該權限用於終止Server服務器,如果被濫用可被用於關閉Server來達到拒絕服務的目的 。 
    * PROCESS:該權限可用於查看當前正在執行的語句的純文本,包括設置或更改密碼的語句文本 。 
    * SUPER:該權限可用於終止其他用戶會話或更改服務器的運行方式。詳見上述SUPER解釋項。

3、 帳號命名規則 

MySQL的帳戶由用戶名和主機名兩部分組成(例如:user_name@host_name)。採用這種方式Server就可以區分相同用戶來自不同主機的連接,本小節將介紹如何編寫有效的帳戶名稱(包括特殊值和通配符規則),對於使用SQL語句CREATE USER、GRANT和SET PASSWORD來操作用戶的,都遵循以下規則:

  • 帳戶名稱構成語法:'user_name'@'host_name'

  • 僅由用戶名組成的帳戶名相當於'user_name'@'%'。例如:'me'相當於'me'@'%'

  • 如果用戶名稱和主機名稱的字符串是合法的非引用標識符(即,不包含sql中的關鍵字或命令字),則不需要使用反撇進行引用。如果用戶名或主機名的字符串中包含特殊字符(如空格或者- 符號)或者通配符(如:點號或者%號),則需要使用單引號或者雙引號引起來,例如:'test-user'@'%.com'(注意:一旦使用引號,注意'me@localhost'和'me'@'localhost'的含義是不同的,'me@localhost' 實際上在使用的時候,MySQL是解析爲'me@localhost'@'%' ,而不是'me'@'localhost'),如果用戶名或主機名不包含引用字符或特殊字符等,可不需要使用分撇和引號,但爲了規範起見,建議至少對主機名和用戶名使用引號,例如:'me'@'localhost'

  • 對CURRENT_USER關鍵字和CURRENT_USER()函數在查詢語句中的效果相同,例如:select current_user; 和 select current_user(); 兩個語句的查詢結果相同,都是返回當前連接的帳號名。

MySQL 中的帳號名在mysql系統字典庫中的權限表user 表中存儲時,會將user_name和host_name分開存儲在user和host兩列中:

  • user表中存儲的帳號信息中,每個帳號包含一行記錄。user和host列存儲帳號對應的用戶名和主機名,其他列存儲了帳號對應的權限和帳號的其他屬性信息。

  • 其他權限表保存着帳戶對實例中的庫級別,表級別,列級別等權限信息。這些表與user表一樣,也使用user和host列來分別存儲帳號對應用戶名和主機名。這些表保存着不同權限作用域的權限信息等(例如:db、columns_priv、procs_priv、proxies_priv、tables_priv,但這些表中並不保存密碼信息)。

  • 爲了進行帳號的訪問檢查,用戶名嚴格區分大小寫,但主機名不區分大小寫。

關於帳號用戶名和主機名中某些特殊值或通配符約定,如下:

  • 默認情況下,user表中保存着一些匿名帳號,所以,默認情況下MySQL允許匿名帳號連接(即,user_name爲空的帳號,但使用匿名帳號需要使用引號,如:''@ localhost')。

  • 帳戶名稱中的host_name部分可以使用多種形式,並且允許使用通配符,如下: 

    * 主機名字符串可以是域名或操作系統主機名(需要DNS解析服務),也可以是IP地址(IPv4或IPv6)。對於域名,'localhost'表示本地主機,“127.0.0.1”表示IPv4的環回接口,':: 1'表示IPv6的環回接口 。

* 主機名或IP地址值中都允許使用通配符%和_。這些與LIKE運算符中的通配符含義相同。例如,“%”表示匹配任意主機名,而“%.mysql.com”表示匹配mysql.com域中的任何主機,'192.51.100.%'表示匹配C類私有網絡192.51.100中的任意主機,由於主機名允許使用IP+通配符值(例如:“192.51.100.%”匹配192.51.100子網上的任意主機),爲了阻止有人通過192.51.100.somewhere.com 格式的主機名字符串構造來嘗試掃描存活主機,MySQL不會在以數字和點開頭的主機名上執行匹配動作。例如:如果主機名部分爲1.2.example.com,則直接被MySQL忽略, IP地址只能使用通配符組合,而不能與主機名進行組合,否則也會被忽略 。 
* 對於指定爲IPv4地址的主機名,可以結合子網掩碼來控制子網IP數量(注意:子網掩碼不使用IPV6),格式:host_ip/netmask。例如:CREATE USER 'david'@'192.51.100.0/255.255.255.0';,表示用戶名爲david,主機名爲192.51.100.0子網下的任意主機,滿足此條件的客戶端主機IP地址範圍從192.51.100.0到192.51.100.255。

對於 MySQL帳號名的主機名 部分爲IP時,子網掩碼ABC網絡都支持,例如:

192.0.0.0/255.0.0.0:掩碼8位,表示192 A類網絡上的任何主機。

192.51.100.0/255.255.0.0:掩碼16位,表示192.51 B類網絡上的任何主機。

192.51.100.0/255.255.255.0:掩碼24位,表示192.51.100 C類網絡上的任何主機。

192.51.100.1:不帶掩碼,表示僅匹配具有此特定IP地址的主機。

MySQL Server使用DNS解析時,需要注意以下問題:

  • 假設本地網絡上的主機具有host1.example.com的完全限定名稱(DNS地址)。如果DNS將此主機解析爲host1.example.com返回,則在MySQL帳號名的主機名部分也需要使用host1.example.com,如果DNS解析僅返回爲host1,則在MySQL帳號名的主機名部分也需要使用host1,否則會被拒絕連接。

  • 如果DNS返回的是IP地址192.51.100.2,那麼它將優先進行IP地址的精確匹配,然後匹配對應網絡的通配符,但不匹配非法的IP地址(例如:192.51.100.2)或子網(例如:192.51.100.%)。

4、MySQL 帳號訪問控制兩階段

4.1. 第一階段(帳號和密碼認證)

當您嘗試連接MySQL Server時,Server根據如下條件來決定是否需要接受或拒絕連接:

  • 您的身份信息(帳號名,由user_name@host_name格式組成)以及密碼信息是否可以驗證通過。

  • 你的帳戶是否處於鎖定狀態。

當MySQL Server接收到一個新的連接請求時,Server首先檢查用戶憑證(帳號+密碼),然後檢查帳戶的鎖定狀態。任意一個步驟檢查失敗則拒絕連接發訪問。如果兩個步驟都通過檢查,則進入第2階段並等待執行請求。

  • MySQL Server 使用user表中的Host、User、authentication_string三個列存儲的用戶憑證信息來執行憑證檢查。 用戶的鎖定狀態記錄在user表的account_locked列中。 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
root@localhost : (none) 12:43:38> select     host,user,authentication_string,account_locked from mysql.user;
+-----------+---------------+----------------------------------------    ---+----------------+
| host      | user          | authentication_string                         | account_locked |
+-----------+---------------+----------------------------------------    ---+----------------+
| localhost | root          |     *3B3D7D2FD587C29C730F36CD52B4BA8CCF4C744F | N              |
| localhost | mysql.session |     *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | Y              |
| localhost | mysql.sys     |     *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | Y              |
| %         | admin         |     *3B3D7D2FD587C29C730F36CD52B4BA8CCF4C744F | N              |
| %         | repl          |     *3B3D7D2FD587C29C730F36CD52B4BA8CCF4C744F | N              |
| %         | qbench        |     *1966B10B87AA6A1F8E1215A1C81DDD5FBBA6B0D0 | N              |
| %         | program       |     *3B3D7D2FD587C29C730F36CD52B4BA8CCF4C744F | N              |
+-----------+---------------+----------------------------------------    ---+----------------+
rows in set (0.00 sec)
# 帳戶鎖定狀態可以通過ALTER USER語句進行更改
ALTER USER [IF EXISTS]
    user [auth_option] [, user [auth_option]] ...
    [REQUIRE {NONE | tls_option [[AND] tls_option] ...}]
    [WITH resource_option [resource_option] ...]
    [password_option | lock_option] ...
......
lock_option: {
    ACCOUNT LOCK
  | ACCOUNT UNLOCK
}

上文中提到過,用戶的身份信息基於兩部分組成(user_name和host_name),對於身份信息的兩個組成部分,有如下認證規則:

  • 如果用戶名列值不爲空,則用戶嘗試連接時就必須傳入用戶名字符串,且必須完全匹配,如果用戶名列值爲空,則爲空的列值在進行認證時,可以匹配任何用戶名(包括用戶名稱爲空和不爲空的,爲空的用戶名被稱爲匿名用戶)。在帳號訪問控制的第一階段匹配到匿名用戶的,在第二階段認證仍然會使用匿名用戶。

  • 如果密碼信息列authentication_string列爲空,則意味着用戶嘗試連接Server時不需要輸入密碼(注意:密碼信息列與帳號名稱列不同,密碼信息列爲空時,只能匹配空串的密碼,不能匹配任意密碼)。如果Server使用了認證插件對客戶端進行身份驗證,則插件實現的身份驗證方法中可能會,也可能不會使用authentication_string密碼信息列中的密碼字符串。甚至可能還會使用外部密碼認證服務器對MySQL Server進行身份驗證。

  • user表中非空的authentication_string列值表示加密過的密碼字符串(hash加密)。MySQL在authentication_string列中不存儲明文格式的密碼(使用帳戶認證插件實現的密碼散列方法加密)。在連接認證過程中使用加密的密碼來檢查密碼是否正確。從MySQL的角度來看,加密的密碼纔是真正的密碼,所以,非授權情況下,不要隨意讓別人知道你的密碼信息,特別是對mysql庫的訪問權限。

下表列舉了一些user_name和host_name常用的組合:

  • 'fred'@'h1.example.net':表示使用fred用戶從h1.example.net主機連接。

  • ''@'h1.example.net':表示任何用戶從h1.example.net主機連接。

  • 'fred'@'%':表示fredon過戶從任何主機連接。

  • ''@'%':表示任何用戶從任何主機連接。

  • 'fred'%'%.example.net':表示fred用戶從example.net域中的任何主機連接。

  • 'fred'@'x.example.%':表示fred用戶從x.example.net,x.example.com,x.example.edu任意域名後綴的主機連接(但後綴%限制可能不生效)。

  • 'fred'@'192.51.100.177':表示fred用戶從IP地址爲192.51.100.177的主機連接。

  • 'fred'@'192.51.100.%':表示fred用戶從192.51.100 C類子網中的任何主機連接。

  • 'fred'@'192.51.100.0/255.255.255.0':表示fred用戶從192.51.100 C類子網中的任何主機連接。

客戶端傳入Server中的身份標識(主機名和用戶名)可能與用戶表中的多個行記錄匹配成功。當一個用戶嘗試連接Server時,如果在Server的user表中匹配到多個行記錄的身份認證信息,則Server必須確定要能夠確定使用哪一行記錄進行許可(不同的身份信息行記錄可能對應着不同的權限):

  • Server 只要將user表讀入內存,即就會在內存中對用戶信息進行排序。

  • 當客戶端嘗試連接時,Server 會按照內存中排好序的內容依次進行匹配。

  • Server 使用與客戶端主機名和用戶名相匹配的第一行進行授權。

Server 使用的排序規則中,先排序主機列值(越精確的值越靠前,字符串主機名和IP地址是最具體的,另外,IP地址的精確性不會受到掩碼的影響,例如:192.51.100.13和192.51.100.0/255.255.255.0被視爲具有相同的精確度。通配符'%'表示“任何主機”,被視爲精確度較差的主機名。空字符串“'也意味着”任何主機“,但精確度比'%'更差,所以排序在'%'之後)。然後再按照用戶列值進行排序(排序規則跟主機列值類似),host和user兩列的排序規則有點類似與多列索引中的排序規則。

示例一:假設用戶表中記錄的內容如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-
# 當Server將表中的內容讀入內存時,會使用剛剛描述的規則在內存中對用戶信息行進行排序。排序後的結果如下所示:
+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-
# 當客戶端嘗試連接時,Server 會查看在內存中已排好序的用戶身份認證信息,並使用第一個匹配項進行許可。如:對於用戶jeffrey的localhost的主機連接,首先,精確匹配localhost主機列,有兩列匹配,然後再匹配用戶名列,也有兩列(空值和jeffrey),兩列交集最終確定匹配行爲:host=localhost,user='',即''@'localhost'身份

示例二: 假設用戶表中記錄的信息如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| h1.example.net |          | ...
+----------------+----------+-
# 在內存中排序之後的內容如下所示:
+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| h1.example.net |          | ...
| %              | jeffrey  | ...
+----------------+----------+-
# 來自h1.example.net主機的jeffrey用戶的連接與第一行記錄匹配成功,而來自任何主機的jeffrey用戶的連接與第二行匹配成功

注意:

  • 通過上述示例可知,當存在匿名用戶的時候,如果您能夠成功連接到服務器,但您的權限可能不符合您的期望,那麼表示您此時可能正在通過其他帳戶進行身份驗證。 可以使用select current_user();或者select current_user;語句來檢查你當前登錄成功的帳號身份信息是什麼? 以便確定是否正確對應了權限信息,如下:

1
2
3
4
5
6
mysql> SELECT CURRENT_USER();
+----------------+
CURRENT_USER() |
+----------------+
| @localhost     |
+----------------+

4.2. 第二階段(權限檢查)

當客戶端與MySQL Server 建立連接之後,Server 進入權限訪問控制的第2階段。在第2階段中,客戶端發送給服務端的每個請求,服務端都會檢查請求操作的類型,然後檢查是否有足夠的訪問權限來執行請求操作。該檢查工作依賴於mysql schema下的user、db、tables_priv、columns_priv、procs_priv、proxies_priv權限表中存放的權限信息。

user:該表中的權限作用範圍是全局的,所以該表中相應權限類型列值爲'Y'時,就表示表示對數據庫實例中的所有數據庫表都有該權限,所以,在大多數時候,我們需要根據具體的業務環境需求來給定需要訪問的數據庫對應的權限,而不是投方便直接給所有庫所有表的權限(關於如何給定權限,請參考上文提到的權限分類)。

  • user列爲空時表示匿名用戶,非空值必須匹配字符串字面本身表示的用戶名,用戶名不能使用通配符。

  • host列值不允許爲空(雖然授權語句和創建用戶的語句可以只寫用戶名而不寫主機名,但實際上存儲在表中時會被轉換爲%),但可以使用通配符(%和_: %表示任意主機,_表示主機名中的任意一個字符),可以使用like關鍵字來配合通配符進行匹配。

db:該表中的權限作用範圍是數據庫級別,對應數據庫內的所有對象:

  • user列和host列的表現形式要求與user表相同。

  • PS: 與user表類似,Server會在啓動時就將db表中的內容讀入內存,並在內存中進行排序,根據Host,Db和User 三列對db表中的數據進行排序。 排序會將最具體的值放在最前面,將最不具體的值放到最後,當Server進行用戶匹配查找時,會使用第一個匹配行進行許可。

tables_priv,columns_priv和procs_priv:這三張表中記錄着表級別權限、列級別權限、線程級別權限:

  • user列和host列的表現形式要求與user表相同。

  • Db,Table_name,Column_name和Routine_name列不能包含通配符或爲空值。

  • PS: 與user表類似,Server會在啓動時就將db表中的內容讀入內存,並在內存中進行排序,根據Host,Db和User三列對tables_priv,columns_priv和procs_priv表數據進行排序。

當一個客戶端連接在進行第二階段權限驗證時,首先檢查user表,如果所檢查權限是user表特有的(其他權限表沒有的權限類別),則user表中允許執行則Server 授予客戶端訪問權限,否則直接拒絕而不會繼續檢查其他權限表(因爲其他權限表不具備該權限列表,無需檢查),如果所檢查權限類別除了在user表之外,在其他權限表中也具有該權限類別(例如:DML權限),則即時在user表中不允許(畢竟user表中的權限是表示是否具有全局權限的意思),也會繼續往下檢查db表,然後再檢查tables_priv表,以此類推。

  • PS:  

    * 如果某客戶端在user表中類似DML權限不足,而在其他db、tables_priv、columns_priv表中都沒有找到對應的user,host列記錄(則表示用戶在所有權限表中都沒有對應操作類型的權限),則客戶端訪問被拒絕,返回無訪問權限提示信息 。

* grant語句在授予用戶權限時,授予庫級別權限時,數據庫不需要事先存在即可授權成功,但如果是對錶級別對象授權,則表需要事先存在,否則授權失敗,提示表不存在的報錯信息 。 
* 對於存儲程序的請求操作,Server 使用procs_priv表檢查權限,而不是tables_priv和columns_priv表。

上文中提及的權限檢查邏輯,可以使用如下布爾型的僞代碼來表示:

1
2
3
4
5
global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges
OR routine privileges

PS:某些類型的一個語句可以需要請求多個類型的權限,例如:INSERT...SELECT,該語句需要請求INSERT和SELECT兩個權限,而這兩個權限可能在授予用戶的時候授予範圍不同,假如INSERT授予的是全局範圍權限,而SELECT是授予的db級別的權限,此時,INSERT權限是保存在user表中的,SELECT權限是保存在db表中的,那麼也就是說,這個時候Server需要分兩次查詢之後將兩個表中記錄的權限信息進行組合,然後再用於判斷用戶是否具INSERT...SELECT語句的訪問請求權限,並返回相應的請求結果。如果任意一個權限不滿足,則拒絕訪問。

5、權限變更的影響

當mysqld啓動時,將讀取所有權限表的內容到內存中。後續所有用戶對MySQL Server的訪問的權鑑都是基於內存中保存的這些值進行。

  • 如果在MySQL Server運行期間使用帳戶管理語句(如GRANT,REVOKE,SET PASSWORD或RENAME USER)間接修改了權限表,則Server會立即將權限表中的內容重新加載到內存中。

  • 如果在MySQL Server運行期間使用INSERT,UPDATE或DELETE等語句直接修改權限表,那麼對權限表的更改不會立即生效,除非重新啓動Server或使用flush privileges;語句或者mysqladmin flush-privileges|reload等命令來重新加載權限表。

對於權限表的重載,需要注意如下事項:

  • 對於表和列級權限,修改並重載權限表之後,對於已經建立的客戶端連接,會在對錶、列的下一個請求中生效。 對於新建連接,第一個請求即生效。

  • 對於庫級別權限,修改並重載權限表之後,對於已經建立的客戶端連接,會在下一次使用use db_name;語句時生效。 對於新建連接,第一個請求即生效 。

    * PS: 如果回收了某用戶的某庫的權限,但客戶端是已經建立連接的且客戶端當前默認庫正好是已回收權限的庫,則如果客戶端不使用use db_name;語句切換默認庫,對於該客戶端來講可能無法感知到庫級別權限發生了修改。

  • 對於全局權限和密碼的修改,不影響已建立連接的客戶端,只針對重連或新創建的客戶端連接生效。

如果Server 啓動時使用了--skip-grant-tables選項,則Server不會讀權限表,也不會進行任何訪問權限控制,這個時候任何人都可以免密碼登錄數據庫並可以做任何事情,這種情況除非維護時間窗口,否則禁止使用,在這種情況下,如果要重新加載權限表,無需重新啓動,只需要執行flush privileges;語句即可。

6、MySQL 常見連接問題

客戶端無法連接服務器的問題

  • 服務端未啓動,可以通過檢查服務端進程是否存在來排除(ps aux |grep mysqld,如果未啓動則嘗試拉起,如果啓動失敗則檢查錯誤日誌排查原因),通常報錯信息類似如下:

      * TCP/IP方式連接: ERROR 2003: Can't connect to MySQL server on 'host_name' (111)

      * socket方式連接: ERROR 2002: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (111)

  • 客戶端連錯端口,可以通過檢查服務器進程運行的端口(netstat -ln | grep mysqld),找到正確的端口並在客戶端指定連接該端口可以解決。

  • 服務器啓用了--skip-networking選項或者--bind-address = 127.0.0.1選項時,它將僅在本地環回接口上偵聽TCP/IP連接,並且不會接受遠程連接。 去除這些選項並重啓進程可以解決。

  • 服務端防火牆未打開MySQL Server的端口訪問權限,關閉防火牆或者允許MySQL Server的服務端口對外提供服務可以解決。

  • 沒有使用正確的帳號或者密碼連接服務器,通常報錯信息類似: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

  • 如果你的數據庫是第一次初始化,且使用了命令mysqld --initialize-secure來初始化,則會爲root用戶生成一個隨機密碼字符串,在MySQL Server啓動之後需要在error log中搜索password關鍵字,以找到隨機密碼字符串進行登錄(使用該命令初始化會產生一個隨機密碼,如果你不需要該隨機密碼,則可以使用mysqld --initialize-insecure命令來初始化數據庫),否則也會報錯: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

  • 如果你升級了服務端到最新版本,而客戶端沒有做相應的升級,則可能報認證協議不支持的錯誤(最好的辦法是升級客戶端版本,不建議去修改密碼認證插件): Client does not support authentication protocol requested by server; consider upgrading MySQL client

  • 服務端達到了最大用戶連接數參數限制,此時使用具有super權限的管理員帳號登錄數據庫,修改最大連接數。

  • 服務端達到了最大錯誤連接數參數限制,可能反覆嘗試連接的某些客戶端被拒絕連接(例如使用錯誤的帳號或密碼反覆嘗試多次,達到了最大錯誤連接數),此時,使用管理員帳號從其他主機登錄數據庫執行flush hosts;語句刷新主機緩存信息,或者修改最大錯誤連接數參數。鄭州不孕不育醫院×××:http://jbk.39.net/yiyuanzaixian/zztjyy/

PS:MySQL 訪問權限系統有如下限制:

  • 不能明確拒絕給定用戶訪問,只能明確地允許給定用戶的訪問,例如: 使用了正確的帳號和密碼,且從被授予訪問的主機上訪問數據庫。

  • 不能單獨授予用戶只能創建或刪除數據庫中的表,而不能創建或刪除數據庫本身(指定了某用戶對某表的 create和drop權限之後,用戶就能夠創建和刪除該表所在的庫)。

  • 帳號的密碼在Server中的作用域是全局的。 不能使用密碼來與特定對象的訪問權限掛鉤(如數據庫、表或存儲過程與函數等)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章