文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  使用部分撤銷限制權限

8.2.12 使用部分撤銷限制權限

如果啟用 partial_revokes 系統變數,則可以授予全域適用的權限。具體而言,對於具有全域層級權限的使用者,partial_revokes 可讓您撤銷特定結構描述的權限,同時保留其他結構描述的權限。因此施加的權限限制對於管理具有全域權限但不應允許存取特定結構描述的帳戶可能很有用。例如,可以允許帳戶修改任何資料表,但 mysql 系統結構描述中的資料表除外。

注意

為簡潔起見,此處顯示的 CREATE USER 陳述式不包含密碼。對於生產環境用途,請務必指派帳戶密碼。

使用部分撤銷

partial_revokes 系統變數控制是否可以對帳戶施加權限限制。依預設,partial_revokes 處於停用狀態,嘗試部分撤銷全域權限會產生錯誤

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT ON *.* TO u1;
mysql> REVOKE INSERT ON world.* FROM u1;
ERROR 1141 (42000): There is no such grant defined for user 'u1' on host '%'

若要允許 REVOKE 操作,請啟用 partial_revokes

SET PERSIST partial_revokes = ON;

SET PERSIST 會為正在運行的 MySQL 實例設定一個值。它也會儲存該值,使其在後續的伺服器重新啟動後仍然保留。若要在不將該值帶到後續重新啟動的情況下變更正在運行的 MySQL 實例的值,請使用 GLOBAL 關鍵字,而不是 PERSIST。請參閱第 15.7.6.1 節,「SET 變數賦值語法」

啟用 partial_revokes 後,部分撤銷會成功

mysql> REVOKE INSERT ON world.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+------------------------------------------+
| Grants for u1@%                          |
+------------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%`  |
| REVOKE INSERT ON `world`.* FROM `u1`@`%` |
+------------------------------------------+

SHOW GRANTS 會在其輸出中將部分撤銷列為 REVOKE 語句。結果表示 u1 擁有全域的 SELECTINSERT 權限,但 INSERT 無法用於 world 綱要中的表格。也就是說,u1world 表格的存取權限為唯讀。

伺服器會將透過部分撤銷實施的權限限制記錄在 mysql.user 系統表格中。如果帳戶具有部分撤銷,則其 User_attributes 欄位值會具有 Restrictions 屬性

mysql> SELECT User, Host, User_attributes->>'$.Restrictions'
       FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';
+------+------+------------------------------------------------------+
| User | Host | User_attributes->>'$.Restrictions'                   |
+------+------+------------------------------------------------------+
| u1   | %    | [{"Database": "world", "Privileges": ["INSERT"]}] |
+------+------+------------------------------------------------------+
注意

雖然可以對任何綱要強制執行部分撤銷,但特別是對 mysql 系統綱要的權限限制作為防止一般帳戶修改系統帳戶策略的一部分非常有用。請參閱保護系統帳戶免受一般帳戶的操縱

部分撤銷操作受以下條件約束

  • 可以使用部分撤銷對不存在的綱要施加限制,但前提是撤銷的權限是全域授予的。如果權限不是全域授予的,則撤銷不存在的綱要的權限會產生錯誤。

  • 部分撤銷僅在綱要層級適用。您無法將部分撤銷用於僅在全域適用的權限(例如 FILEBINLOG_ADMIN),或用於表格、欄位或常式權限。

  • 在權限指派中,啟用 partial_revokes 會使 MySQL 將綱要名稱中未逸出的 _% SQL 萬用字元解譯為字面字元,就像它們已逸出為 \_\% 一樣。由於這會變更 MySQL 解譯權限的方式,因此對於可能啟用 partial_revokes 的安裝,建議避免在權限指派中使用未逸出的萬用字元。

如先前所述,綱要層級權限的部分撤銷會在 SHOW GRANTS 輸出中顯示為 REVOKE 語句。這與 SHOW GRANTS 如何表示「普通」綱要層級權限不同

  • 授予後,綱要層級權限會在輸出中由其自己的 GRANT 語句表示

    mysql> CREATE USER u1;
    mysql> GRANT UPDATE ON mysql.* TO u1;
    mysql> GRANT DELETE ON world.* TO u1;
    mysql> SHOW GRANTS FOR u1;
    +---------------------------------------+
    | Grants for u1@%                       |
    +---------------------------------------+
    | GRANT USAGE ON *.* TO `u1`@`%`        |
    | GRANT UPDATE ON `mysql`.* TO `u1`@`%` |
    | GRANT DELETE ON `world`.* TO `u1`@`%` |
    +---------------------------------------+
  • 撤銷時,綱要層級權限只會從輸出中消失。它們不會顯示為 REVOKE 語句

    mysql> REVOKE UPDATE ON mysql.* FROM u1;
    mysql> REVOKE DELETE ON world.* FROM u1;
    mysql> SHOW GRANTS FOR u1;
    +--------------------------------+
    | Grants for u1@%                |
    +--------------------------------+
    | GRANT USAGE ON *.* TO `u1`@`%` |
    +--------------------------------+

當使用者授予權限時,受讓人會繼承授予者對權限的任何限制,除非受讓人已擁有該權限且沒有限制。請考慮以下兩個使用者,其中一個使用者擁有全域的 SELECT 權限

CREATE USER u1, u2;
GRANT SELECT ON *.* TO u2;

假設管理使用者 admin 擁有全域但部分撤銷的 SELECT 權限

mysql> CREATE USER admin;
mysql> GRANT SELECT ON *.* TO admin WITH GRANT OPTION;
mysql> REVOKE SELECT ON mysql.* FROM admin;
mysql> SHOW GRANTS FOR admin;
+------------------------------------------------------+
| Grants for admin@%                                   |
+------------------------------------------------------+
| GRANT SELECT ON *.* TO `admin`@`%` WITH GRANT OPTION |
| REVOKE SELECT ON `mysql`.* FROM `admin`@`%`          |
+------------------------------------------------------+

如果 admin 全域授予 SELECTu1u2,則每個使用者的結果都不同

  • 如果 admin 全域授予 SELECT 給一開始沒有 SELECT 權限的 u1,則 u1 會繼承 admin 權限限制

    mysql> GRANT SELECT ON *.* TO u1;
    mysql> SHOW GRANTS FOR u1;
    +------------------------------------------+
    | Grants for u1@%                          |
    +------------------------------------------+
    | GRANT SELECT ON *.* TO `u1`@`%`          |
    | REVOKE SELECT ON `mysql`.* FROM `u1`@`%` |
    +------------------------------------------+
  • 另一方面,u2 已經擁有全域的 SELECT 權限且沒有限制。GRANT 只能增加受讓人現有的權限,而不能減少它們,因此,如果 admin 全域授予 SELECTu2,則 u2 不會繼承 admin 限制

    mysql> GRANT SELECT ON *.* TO u2;
    mysql> SHOW GRANTS FOR u2;
    +---------------------------------+
    | Grants for u2@%                 |
    +---------------------------------+
    | GRANT SELECT ON *.* TO `u2`@`%` |
    +---------------------------------+

如果 GRANT 語句包含 AS user 子句,則套用的權限限制是該子句指定的使用者/角色組合的權限限制,而不是執行語句的使用者的權限限制。如需關於 AS 子句的資訊,請參閱第 15.7.1.6 節,「GRANT 語句」

授予帳戶的新權限限制會新增至該帳戶的任何現有限制

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO u1;
mysql> REVOKE INSERT ON mysql.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@%                                         |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE INSERT ON `mysql`.* FROM `u1`@`%`                |
+---------------------------------------------------------+
mysql> REVOKE DELETE, UPDATE ON db2.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@%                                         |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE UPDATE, DELETE ON `db2`.* FROM `u1`@`%`          |
| REVOKE INSERT ON `mysql`.* FROM `u1`@`%`                |
+---------------------------------------------------------+

權限限制的彙總適用於權限被明確部分撤銷時(如剛才所示),以及從執行語句的使用者或 AS user 子句中提到的使用者隱式繼承限制時。

如果帳戶對綱要具有權限限制

  • 該帳戶無法將受限綱要或其中任何物件的權限授予其他帳戶。

  • 另一個沒有該限制的帳戶可以將受限綱要或其中物件的權限授予受限帳戶。假設一個不受限制的使用者執行這些語句

    CREATE USER u1;
    GRANT SELECT, INSERT, UPDATE ON *.* TO u1;
    REVOKE SELECT, INSERT, UPDATE ON mysql.* FROM u1;
    GRANT SELECT ON mysql.user TO u1;          -- grant table privilege
    GRANT SELECT(Host,User) ON mysql.db TO u1; -- grant column privileges

    產生的帳戶具有以下權限,並能夠在受限綱要中執行有限的操作

    mysql> SHOW GRANTS FOR u1;
    +-----------------------------------------------------------+
    | Grants for u1@%                                           |
    +-----------------------------------------------------------+
    | GRANT SELECT, INSERT, UPDATE ON *.* TO `u1`@`%`           |
    | REVOKE SELECT, INSERT, UPDATE ON `mysql`.* FROM `u1`@`%`  |
    | GRANT SELECT (`Host`, `User`) ON `mysql`.`db` TO `u1`@`%` |
    | GRANT SELECT ON `mysql`.`user` TO `u1`@`%`                |
    +-----------------------------------------------------------+

如果帳戶對全域權限具有限制,則以下任何操作都會移除該限制

  • 由對權限沒有限制的帳戶將權限全域授予該帳戶。

  • 在綱要層級授予權限。

  • 全域撤銷權限。

考慮一個使用者 u1,他擁有數個全域權限,但對 INSERTUPDATEDELETE 有限制

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO u1;
mysql> REVOKE INSERT, UPDATE, DELETE ON mysql.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+----------------------------------------------------------+
| Grants for u1@%                                          |
+----------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%`  |
| REVOKE INSERT, UPDATE, DELETE ON `mysql`.* FROM `u1`@`%` |
+----------------------------------------------------------+

從沒有限制的帳戶將權限全域授予 u1 會移除權限限制。例如,若要移除 INSERT 限制

mysql> GRANT INSERT ON *.* TO u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@%                                         |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE UPDATE, DELETE ON `mysql`.* FROM `u1`@`%`        |
+---------------------------------------------------------+

在綱要層級將權限授予 u1 會移除權限限制。例如,若要移除 UPDATE 限制

mysql> GRANT UPDATE ON mysql.* TO u1;
mysql> SHOW GRANTS FOR u1;
+---------------------------------------------------------+
| Grants for u1@%                                         |
+---------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO `u1`@`%` |
| REVOKE DELETE ON `mysql`.* FROM `u1`@`%`                |
+---------------------------------------------------------+

撤銷全域權限會移除該權限,包括對該權限的任何限制。例如,若要移除 DELETE 限制(以移除所有 DELETE 存取權為代價)

mysql> REVOKE DELETE ON *.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+-------------------------------------------------+
| Grants for u1@%                                 |
+-------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE ON *.* TO `u1`@`%` |
+-------------------------------------------------+

如果帳戶同時具有全域和綱要層級的權限,您必須在綱要層級撤銷兩次才能產生部分撤銷。假設 u1 具有以下權限,其中 INSERT 同時在全域和 world 綱要上持有

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT ON *.* TO u1;
mysql> GRANT INSERT ON world.* TO u1;
mysql> SHOW GRANTS FOR u1;
+-----------------------------------------+
| Grants for u1@%                         |
+-----------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%` |
| GRANT INSERT ON `world`.* TO `u1`@`%`   |
+-----------------------------------------+

world 上撤銷 INSERT 會撤銷綱要層級權限(SHOW GRANTS 不再顯示綱要層級的 GRANT 語句)

mysql> REVOKE INSERT ON world.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+-----------------------------------------+
| Grants for u1@%                         |
+-----------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%` |
+-----------------------------------------+

再次在 world 上撤銷 INSERT 會執行全域權限的部分撤銷(SHOW GRANTS 現在包含綱要層級的 REVOKE 語句)

mysql> REVOKE INSERT ON world.* FROM u1;
mysql> SHOW GRANTS FOR u1;
+------------------------------------------+
| Grants for u1@%                          |
+------------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%`  |
| REVOKE INSERT ON `world`.* FROM `u1`@`%` |
+------------------------------------------+

部分撤銷與明確綱要授權

若要為某些綱要提供帳戶存取權,而不是其他綱要,部分撤銷提供了一種替代方法,可以明確授予綱要層級存取權,而不授予全域權限。這兩種方法各有優缺點。

授予綱要層級權限而不授予全域權限

  • 新增綱要:預設情況下,現有帳戶無法存取該綱要。對於任何應可存取該綱要的帳戶,DBA 必須授予綱要層級存取權。

  • 新增帳戶:DBA 必須為帳戶應具有存取權的每個綱要授予綱要層級存取權。

結合部分撤銷授予全域權限

  • 新增綱要:具有全域權限的現有帳戶可以存取該綱要。對於任何此類不應存取該綱要的帳戶,DBA 必須新增部分撤銷。

  • 新增帳戶:DBA 必須授予全域權限,以及每個受限綱要的部分撤銷。

對於存取權僅限於少數綱要的帳戶,使用明確綱要層級授予的方法更方便。對於廣泛存取所有綱要(少數除外)的帳戶,使用部分撤銷的方法更方便。

停用部分撤銷

一旦啟用,如果任何帳戶具有權限限制,則無法停用 partial_revokes。如果存在任何此類帳戶,停用 partial_revokes 會失敗

若要在存在限制時停用 partial_revokes,必須先移除限制

  1. 判斷哪些帳戶具有部分撤銷

    SELECT User, Host, User_attributes->>'$.Restrictions'
    FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';
  2. 對於每個此類帳戶,移除其權限限制。假設上一個步驟顯示帳戶 u1 具有以下限制

    [{"Database": "world", "Privileges": ["INSERT", "DELETE"]

    可以使用各種方式移除限制

    • 全域授予權限,沒有限制

      GRANT INSERT, DELETE ON *.* TO u1;
    • 在綱要層級授予權限

      GRANT INSERT, DELETE ON world.* TO u1;
    • 全域撤銷權限(假設不再需要它們)

      REVOKE INSERT, DELETE ON *.* FROM u1;
    • 移除帳戶本身(假設不再需要它)

      DROP USER u1;

移除所有權限限制後,即可停用部分撤銷

SET PERSIST partial_revokes = OFF;

部分撤銷和複製

在複製情境中,如果任何主機上啟用 partial_revokes,則必須在所有主機上啟用。否則,對全域權限進行部分撤銷的 REVOKE 陳述式,在發生複製的所有主機上不會有相同的效果,可能導致複製不一致或錯誤。

當啟用 partial_revokes 時,二進制日誌中會為 GRANT 陳述式記錄擴展語法,包括發出該陳述式的目前使用者及其目前活動的角色。如果以這種方式記錄的使用者或角色在副本上不存在,則複製應用程式執行緒會在 GRANT 陳述式處停止並產生錯誤。請確保在複製來源伺服器上發出或可能發出 GRANT 陳述式的所有使用者帳戶,也存在於副本上,並且具有與來源上相同的角色集。