1. 程式人生 > >MySQL使用者賬戶管理與許可權管理詳解

MySQL使用者賬戶管理與許可權管理詳解

MySQL 的許可權表在資料庫啟動的時候就載入記憶體,當用戶通過身份認證後,就在記憶體中進行相應許可權的存取,這樣,此使用者就可以在資料庫中做許可權範圍內的各種操作了。

mysql 的許可權體系大致分為5個層級:
全域性層級

全域性許可權適用於一個給定伺服器中的所有資料庫。這些許可權儲存在mysql.user表中。GRANT ALL ON *.*和REVOKE ALL ON *.*只授予和撤銷全域性許可權。

資料庫層級
資料庫許可權適用於一個給定資料庫中的所有目標。這些許可權儲存在mysql.db和mysql.host表中。GRANT ALL ON db_name.*和REVOKE ALL ON db_name.*只授予和撤銷資料庫許可權。

表層級
表許可權適用於一個給定表中的所有列。這些許可權儲存在mysql.talbes_priv表中。GRANT ALL ON db_name.tbl_name和REVOKE ALL ON db_name.tbl_name只授予和撤銷表許可權。

列層級
列許可權適用於一個給定表中的單一列。這些許可權儲存在mysql.columns_priv表中。當使用REVOKE時,您必須指定與被授權列相同的列。

子程式層級
CREATE ROUTINE, ALTER ROUTINE, EXECUTE和GRANT許可權適用於已儲存的子程式。這些許可權可以被授予為全域性層級和資料庫層級。而且,除了CREATE ROUTINE外,這些許可權可以被授予為子程式層級,並存儲在mysql.procs_priv表中。

這些許可權資訊儲存在下面的系統表中:

mysql.user
mysql.db
mysql.host
mysql.table_priv
mysql.column_priv

當用戶連線進來,mysqld會通過上面的這些表對使用者許可權進行驗證!

一、許可權表的存取

在許可權存取的兩個過程中,系統會用到 “mysql” 資料庫(安裝 MySQL 時被建立,資料庫名稱叫“mysql”) 中 user、host 和 db 這3個最重要的許可權表。

在這 3 個表中,最重要的表示 user 表,其次是 db 表,host 表在大多數情況下並不使用。

user 中的列主要分為 4 個部分:使用者列、許可權列、安全列和資源控制列。

通常用的最多的是使用者列和許可權列,其中許可權列又分為普通許可權和管理許可權。普通許可權用於資料庫的操作,比如 select_priv、super_priv 等。

當用戶進行連線時,許可權表的存取過程有以下兩個過程:

先從 user 表中的 host、user 和 password 這 3 個欄位中判斷連線的 IP、使用者名稱、和密碼是否存在於表中,如果存在,則通過身份驗證,否則拒絕連線。
如果通過身份驗證、則按照以下許可權表的順序得到資料庫許可權:user -> db -> tables_priv -> columns_priv。
在這幾個許可權表中,許可權範圍依次遞減,全域性許可權覆蓋區域性許可權。上面的第一階段好理解,下面以一個例子來詳細解釋一下第二階段。
為了方便測試,需要修改變數 sql_mode,不然會報錯,如下

MySQL [(none)]> grant select on *.* to 
[email protected]
; ERROR 1133 (42000): Can't find any matching row in the user table MySQL [(none)]> SET SESSION sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'; Query OK, 0 rows affected, 2 warnings (0.07 sec) MySQL [(none)]> grant select on *.* to [email protected]; Query OK, 0 rows affected, 2 warnings (0.10 sec)
// sql_mode 預設值中有 NO_AUTO_CREATE_USER (防止GRANT自動建立新使用者,除非還指定了密碼)
SET SESSION sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';
1. 建立使用者

[email protected],並賦予所有資料庫上的所有表的 select 許可權

先檢視user表顯示的許可權狀態
MySQL [mysql]>  select * from user where user="xxx" and host='localhost' \G;
*************************** 1. row ***************************
                  Host: localhost
                  User: xxx
           Select_priv: Y
           Insert_priv: N
           Update_priv: N
           Delete_priv: N
           Create_priv: N
             Drop_priv: N
           Reload_priv: N
         Shutdown_priv: N
          Process_priv: N
             File_priv: N
            Grant_priv: N
       References_priv: N
            Index_priv: N
            Alter_priv: N
          Show_db_priv: N
            Super_priv: N
 Create_tmp_table_priv: N
      Lock_tables_priv: N
          Execute_priv: N
       Repl_slave_priv: N
      Repl_client_priv: N
      Create_view_priv: N
        Show_view_priv: N
   Create_routine_priv: N
    Alter_routine_priv: N
      Create_user_priv: N
            Event_priv: N
          Trigger_priv: N
Create_tablespace_priv: N
              ssl_type: 
            ssl_cipher: 
           x509_issuer: 
          x509_subject: 
         max_questions: 0
           max_updates: 0
       max_connections: 0
  max_user_connections: 0
                plugin: mysql_native_password
 authentication_string: 
      password_expired: N
 password_last_changed: 2018-12-03 17:34:49
     password_lifetime: NULL
        account_locked: N
再檢視db表的許可權狀態
MySQL [mysql]>  select * from db where user="xxx" and host='localhost' \G;
Empty set (0.03 sec)

可以發現user表中Select_priv: Y,其他均為N

DB表中則無記錄

也就是說,對所有資料庫都具有相同的許可權的使用者並不需要記錄到 db 表,而僅僅需要將 user 表中的 select_priv 改為 “Y” 即可。換句話說,user 表中的每個許可權都代表了對所有資料庫都有許可權

2. 將 [email protected] 上的許可權改為只對 db1 資料庫上所有表的 select 許可權。
MySQL [mysql]> create database db1;
Query OK, 1 row affected (0.01 sec)

MySQL [mysql]> re^C
MySQL [mysql]>  revoke select on *.* from [email protected];
Query OK, 0 rows affected, 1 warning (0.06 sec)

MySQL [mysql]> grant select on db1.* to [email protected];
Query OK, 0 rows affected, 1 warning (0.09 sec)

MySQL [mysql]> select * from user where user='xxx'\G;
*************************** 1. row ***************************
                  Host: localhost
                  User: xxx
           Select_priv: N
           Insert_priv: N
           Update_priv: N
           Delete_priv: N
           Create_priv: N
             Drop_priv: N
           Reload_priv: N
MySQL [mysql]> select * from db where user='xxx'\G;
*************************** 1. row ***************************
                 Host: localhost
                   Db: db1
                 User: xxx
          Select_priv: Y
          Insert_priv: N
          Update_priv: N
          Delete_priv: N
          Create_priv: N
            Drop_priv: N
           Grant_priv: N
      References_priv: N
           Index_priv: N
           Alter_priv: N
Create_tmp_table_priv: N
     Lock_tables_priv: N
     Create_view_priv: N
       Show_view_priv: N
  Create_routine_priv: N
   Alter_routine_priv: N
         Execute_priv: N
           Event_priv: N
         Trigger_priv: N

這時候發現,user 表中的 select_priv 變為 “N” ,而 db 表中增加了 dbxxx 的一條記錄。也就是說,當只授予部分資料庫某些許可權時,user 表中的相應許可權列保持 “N”,而將具體的資料庫許可權寫入 db 表。tablecolumn 的許可權機制和 db 類似。

3. tables_priv記錄表許可權
MySQL [db1]> create table t1(id int(10),name char(10));
Query OK, 0 rows affected (0.83 sec)

MySQL [db1]> grant select on db1.t1 to [email protected];
Query OK, 0 rows affected, 2 warnings (0.06 sec)

MySQL [mysql]> select * from user where user='mmm'\G;
*************************** 1. row ***************************
                  Host: localhost
                  User: mmm
           Select_priv: N
           Insert_priv: N
           Update_priv: N
           Delete_priv: N
           Create_priv: N
             Drop_priv: N
           Reload_priv: N
...

MySQL [mysql]> select * from db where user='mmm'\G;
Empty set (0.00 sec)


MySQL [mysql]> select * from tables_priv where user='mmm'\G;
*************************** 1. row ***************************
       Host: localhost
         Db: db1
       User: mmm
 Table_name: t1
    Grantor: [email protected]
  Timestamp: 0000-00-00 00:00:00
 Table_priv: Select
Column_priv: 
1 row in set (0.00 sec)

ERROR: 
No query specified

MySQL [mysql]> select * from columns_priv where user='mmm'\G;
Empty set (0.00 sec)

可以看見tables_priv表中增加了一條記錄,而在user db columns_priv三個表中沒有記錄

從上例可以看出,當用戶通過許可權認證,進行許可權分配時,將按照 ==user -> db -> tables_priv -> columns_priv== 的順序進行許可權分配,即先檢查全域性許可權表 user,如果 user 中對應 許可權為 “Y”,則此使用者對所有資料庫的許可權都為“Y”,將不再檢查 dbtables_privcolumns_priv;如果為“N”,則到 db 表中檢查此使用者對應的具體資料庫,並得到 db 中為 “Y”的許可權;如果 db 中相應許可權為 “N”,則再依次檢查tables_privcolumns_priv 中的許可權,如果所有的都為“N”,則判斷為不具備許可權。

二. 賬戶管理

授權 grant

grant不僅可以用來授權,還可以用來建立使用者。

授權的語法:

grant 許可權列表 on 庫名.表名 to 使用者@主機 identified by '密碼';
建立使用者 p1 ,許可權為可以在所有資料庫上執行所有許可權,只能從本地進行連線
MySQL [mysql]> grant all privileges on *.* to [email protected];
Query OK, 0 rows affected, 2 warnings (0.03 sec)

MySQL [mysql]> select * from user where user='p1'\G
*************************** 1. row ***************************
                  Host: localhost
                  User: p1
           Select_priv: Y
           Insert_priv: Y
           Update_priv: Y
           Delete_priv: Y
           Create_priv: Y
             Drop_priv: Y
           Reload_priv: Y
         Shutdown_priv: Y
          Process_priv: Y
             File_priv: Y
            Grant_priv: N
       References_priv: Y
            Index_priv: Y
            Alter_priv: Y
          Show_db_priv: Y
            Super_priv: Y
 Create_tmp_table_priv: Y
      Lock_tables_priv: Y
          Execute_priv: Y
       Repl_slave_priv: Y
      Repl_client_priv: Y
      Create_view_priv: Y
        Show_view_priv: Y
   Create_routine_priv: Y
    Alter_routine_priv: Y
      Create_user_priv: Y
            Event_priv: Y
          Trigger_priv: Y
Create_tablespace_priv: Y
              ssl_type: 
            ssl_cipher: 
           x509_issuer: 
          x509_subject: 
         max_questions: 0
           max_updates: 0
       max_connections: 0
  max_user_connections: 0
                plugin: mysql_native_password
 authentication_string: 
      password_expired: N
 password_last_changed: 2018-12-03 18:11:01
     password_lifetime: NULL
        account_locked: N
1 row in set (0.00 sec)

除了 grant_priv 許可權外,所有許可權在user 表裡面都是 “Y”。

增加對 p1 的 grant 許可權
MySQL [mysql]> grant all privileges on *.* to [email protected] with grant option;
Query OK, 0 rows affected, 1 warning (0.03 sec)

MySQL [mysql]> select * from user where user='p1'\G
*************************** 1. row ***************************
                  Host: localhost
                  User: p1
           Select_priv: Y
           Insert_priv: Y
           Update_priv: Y
           Delete_priv: Y
           Create_priv: Y
             Drop_priv: Y
           Reload_priv: Y
         Shutdown_priv: Y
          Process_priv: Y
             File_priv: Y
            Grant_priv: Y
       References_priv: Y
            Index_priv: Y
            Alter_priv: Y
          Show_db_priv: Y
            Super_priv: Y
 Create_tmp_table_priv: Y
      Lock_tables_priv: Y
          Execute_priv: Y
       Repl_slave_priv: Y
      Repl_client_priv: Y
      Create_view_priv: Y
        Show_view_priv: Y
   Create_routine_priv: Y
    Alter_routine_priv: Y
      Create_user_priv: Y
            Event_priv: Y
          Trigger_priv: Y
Create_tablespace_priv: Y
              ssl_type: 
            ssl_cipher: 
           x509_issuer: 
          x509_subject: 
         max_questions: 0
           max_updates: 0
       max_connections: 0
  max_user_connections: 0
                plugin: mysql_native_password
 authentication_string: 
      password_expired: N
 password_last_changed: 2018-12-03 18:11:01
     password_lifetime: NULL
        account_locked: N
1 row in set (0.00 sec)
設定密碼賦予grant許可權
MySQL [mysql]> grant all  privileges on *.* to [email protected] identified by '123' with grant option;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

MySQL [mysql]> select * from user where user='p1'\G
*************************** 1. row ***************************
                  Host: localhost
                  User: p1
           Select_priv: Y
           Insert_priv: Y
           Update_priv: Y
           Delete_priv: Y
           Create_priv: Y
             Drop_priv: Y
           Reload_priv: Y
         Shutdown_priv: Y
          Process_priv: Y
             File_priv: Y
            Grant_priv: Y
       References_priv: Y
            Index_priv: Y
            Alter_priv: Y
          Show_db_priv: Y
            Super_priv: Y
 Create_tmp_table_priv: Y
      Lock_tables_priv: Y
          Execute_priv: Y
       Repl_slave_priv: Y
      Repl_client_priv: Y
      Create_view_priv: Y
        Show_view_priv: Y
   Create_routine_priv: Y
    Alter_routine_priv: Y
      Create_user_priv: Y
            Event_priv: Y
          Trigger_priv: Y
Create_tablespace_priv: Y
              ssl_type: 
            ssl_cipher: 
           x509_issuer: 
          x509_subject: 
         max_questions: 0
           max_updates: 0
       max_connections: 0
  max_user_connections: 0
                plugin: mysql_native_password
 authentication_string: *23AE809DDACAF96AF0FD78ED04B6A265E05AA257
      password_expired: N
 password_last_changed: 2018-12-03 18:14:40
     password_lifetime: NULL
        account_locked: N
1 row in set (0.00 sec)

在5.7版本後的資料庫,密碼欄位改為authentication_string

建立新使用者 p2,可以從任何 IP 連線,許可權為對 db1 資料庫裡的所有表進行 select 、update、insert 和 delete 操作,初始密碼為“123”
MySQL [mysql]> grant select,insert,update,delete on db1.* to 'p2'@'%' identified by '123';
Query OK, 0 rows affected, 1 warning (0.01 sec)

MySQL [mysql]> select * from user where user='p2'\G;
*************************** 1. row ***************************
                  Host: %
                  User: p2
           Select_priv: N
           Insert_priv: N
           Update_priv: N
           Delete_priv: N
           Create_priv: N
             Drop_priv: N
           Reload_priv: N
         Shutdown_priv: N
...
Create_tablespace_priv: N
              ssl_type: 
            ssl_cipher: 
           x509_issuer: 
          x509_subject: 
         max_questions: 0
           max_updates: 0
       max_connections: 0
  max_user_connections: 0
                plugin: mysql_native_password
 authentication_string: *23AE809DDACAF96AF0FD78ED04B6A265E05AA257
      password_expired: N
 password_last_changed: 2018-12-03 18:20:44
     password_lifetime: NULL
        account_locked: N
1 row in set (0.00 sec)

ERROR: 
No query specified

MySQL [mysql]> select * from db where user='p2'\G;
*************************** 1. row ***************************
                 Host: %
                   Db: db1
                 User: p2
          Select_priv: Y
          Insert_priv: Y
          Update_priv: Y
          Delete_priv: Y
          Create_priv: N
            Drop_priv: N
           Grant_priv: N
      References_priv: N
           Index_priv: N
           Alter_priv: N
Create_tmp_table_priv: N
     Lock_tables_priv: N
     Create_view_priv: N
       Show_view_priv: N
  Create_routine_priv: N
   Alter_routine_priv: N
         Execute_priv: N
           Event_priv: N
         Trigger_priv: N
1 row in set (0.00 sec)

user 表中的許可權都是“N”,db 表中增加的記錄許可權則都是“Y”,這樣只授予使用者適當的許可權,而不會授予過多的許可權。

本例中的 IP 限制為所有 IP 都可以連線,因此設定為 “%”,mysql 資料庫中是通過 user 表的 host 欄位來進行控制,host 可以是以下型別的賦值。

注意: mysql 資料庫的 user 表中 host 的值為 “%” 或者空,表示所有外部 IP 都可以連線,但是不包括本地伺服器 localhost,因此,如果要包括本地伺服器,必須單獨為 localhost 賦予許可權。

授予 super、process、file 許可權給使用者 [email protected]%
MySQL [mysql]> grant super,process,file on db1.* to 'p3'@'%';
ERROR 1221 (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES


MySQL [mysql]> grant super,process,file on *.* to 'p3'@'%';
Query OK, 0 rows affected (0.03 sec)

這幾個許可權都是屬於管理許可權,因此不能夠指定某個資料庫,on 後面必須跟 *.*,否則會提示錯誤,如上

那這幾個許可權是幹啥的?
process通過這個許可權,使用者可以執行SHOW PROCESSLISTKILL命令。預設情況下,每個使用者都可以執行SHOW PROCESSLIST命令,但是隻能查詢本使用者的程序。

擁有file許可權才可以執行 select ..into outfileload data infile…操作,但是不要把file, process, super許可權授予管理員以外的賬號,這樣存在嚴重的安全隱患。

super這個許可權允許使用者終止任何查詢;修改全域性變數的SET語句;使用CHANGE MASTER,PURGE MASTER LOGS

另外一個比較特殊的

usage許可權
連線(登陸)許可權,建立一個使用者,就會自動授予其usage許可權(預設授予)。

該許可權只能用於資料庫登陸,不能執行任何操作;且usage許可權不能被回收,也即``REVOKE使用者並不能刪除使用者。

檢視賬號許可權

賬號建立好後,可以通過如下命令檢視許可權:

show grants for [email protected];
MySQL [mysql]> show grants for [email protected]'%';
+-------------------------------------------------------------+
| Grants for [email protected]%                                             |
+-------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'p2'@'%'                              |
| GRANT SELECT, INSERT, UPDATE, DELETE ON `db1`.* TO 'p2'@'%' |
+-------------------------------------------------------------+
2 rows in set (0.00 sec)

更改賬戶許可權

建立使用者賬號p4,許可權為對db1所有表具有select許可權
MySQL [mysql]> grant select on db1.* to [email protected]'%';
Query OK, 0 rows affected, 1 warning (0.01 sec)

MySQL [mysql]> show grants for [email protected]'%';
+-------------------------------------+
| Grants for [email protected]%                     |
+-------------------------------------+
| GRANT USAGE ON *.* TO 'p4'@'%'      |
| GRANT SELECT ON `db1`.* TO 'p4'@'%' |
+-------------------------------------+
2 rows in set (0.00 sec)
增加delete許可權
MySQL [mysql]> grant delete on db1.* to [email protected]'%';
Query OK, 0 rows affected (0.01 sec)

MySQL [mysql]> show grants for [email protected]'%';
+---------------------------------------------+
| Grants for [email protected]%                             |
+---------------------------------------------+
| GRANT USAGE ON *.* TO 'p4'@'%'              |
| GRANT SELECT, DELETE ON `db1`.* TO 'p4'@'%' |
+---------------------------------------------+
2 rows in set (0.00 sec)

和已有的 select 許可權進行合併

刪除delete許可權

revoke 語句可以回收已經賦予的許可權

MySQL [mysql]> show grants for [email protected]'%';
+---------------------------------------------+
| Grants for [email protected]%                             |
+---------------------------------------------+
| GRANT USAGE ON *.* TO 'p4'@'%'              |
| GRANT SELECT, DELETE ON `db1`.* TO 'p4'@'%' |
+---------------------------------------------+
2 rows in set (0.00 sec)

MySQL [mysql]> revoke delete on db1.* from [email protected]'%';
Query OK, 0 rows affected (0.01 sec)

MySQL [mysql]> show grants for [email protected]'%';
+-------------------------------------+
| Grants for [email protected]%                     |
+-------------------------------------+
| GRANT USAGE ON *.* TO 'p4'@'%'      |
| GRANT SELECT ON `db1`.* TO 'p4'@'%' |
+-------------------------------------+
2 rows in set (0.00 sec)

usagerevoke?

MySQL [mysql]> revoke select on db1.* from [email protected]'%';
Query OK, 0 rows affected (0.02 sec)

MySQL [mysql]> show grants for [email protected]'%';
+--------------------------------+
| Grants for [email protected]%                |
+--------------------------------+
| GRANT USAGE ON *.* TO 'p4'@'%' |
+--------------------------------+
1 row in set (0.00 sec)

MySQL [mysql]> revoke usage on db1.* from [email protected]'%';
ERROR 1141 (42000): There is no such grant defined for user 'p4' on host '%'

usage 許可權不能被回收,也就是說,revoke 使用者並不能刪除使用者。

要徹底的刪除賬號,可以使用 drop user

drop user [email protected]'%';

賬號資源限制

建立 MySQL 賬號時,還有一類選項稱為賬號資源限制,這類選項的作用是限制每個賬號實際具有的資源限制,這裡的“資源”主要包括:

max_queries_per_hour count : 單個賬號每小時執行的查詢次數
max_upodates_per_hour count : 單個賬號每小時執行的更新次數
max_connections_per_hour count : 單個賬號每小時連線伺服器的次數
max_user_connections count : 單個賬號併發連線伺服器的次數

注意:
新增使用者或者許可權,使用mysql> flush privileges; 重新整理許可權

具體許可權可以參考官網文件

https://dev.mysql.com/doc/refman/5.7/en/privileges-provided.html