文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美國信紙尺寸) - 39.9Mb
PDF (A4) - 40.0Mb
手冊頁 (TGZ) - 258.5Kb
手冊頁 (Zip) - 365.5Kb
資訊 (Gzip) - 4.0Mb
資訊 (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  基於 SQL 的帳戶活動稽核

8.2.23 基於 SQL 的帳戶活動稽核

應用程式可以使用下列準則來執行基於 SQL 的稽核,將資料庫活動連結到 MySQL 帳戶。

MySQL 帳戶對應於 mysql.user 系統資料表中的列。當用戶端成功連線時,伺服器會將用戶端驗證到此表格中的特定列。此列中的 UserHost 欄值會唯一識別帳戶,並對應於 SQL 陳述式中寫入帳戶名稱的 'user_name'@'host_name' 格式。

用於驗證用戶端的帳戶會決定用戶端擁有的權限。通常,可以呼叫 CURRENT_USER() 函數來確定此用戶端的帳戶。其值是從帳戶的 user 表格列的 UserHost 欄中建構的。

但是,在某些情況下,CURRENT_USER() 的值並非對應於用戶端使用者,而是對應於不同的帳戶。當權限檢查不是基於用戶端的帳戶時,就會發生這種情況

  • 使用 SQL SECURITY DEFINER 特性定義的儲存常式(程序和函數)

  • 使用 SQL SECURITY DEFINER 特性定義的檢視

  • 觸發程序和事件

在這些情況下,會根據 DEFINER 帳戶執行權限檢查,且 CURRENT_USER() 參考該帳戶,而不是參考呼叫儲存常式或檢視,或導致觸發程序啟動的用戶端的帳戶。若要確定呼叫的使用者,您可以呼叫 USER() 函數,它會傳回一個值,指示用戶端提供的實際使用者名稱以及用戶端連線的主機。但是,此值不一定直接對應於 user 表格中的帳戶,因為 USER() 值永遠不包含萬用字元,而帳戶值(如 CURRENT_USER() 所傳回的)可能包含使用者名稱和主機名稱萬用字元。

例如,空白使用者名稱會比對任何使用者,因此 ''@'localhost' 的帳戶可讓用戶端以任何使用者名稱從本機主機匿名連線。在這種情況下,如果用戶端從本機主機以 user1 的身分連線,則 USER()CURRENT_USER() 會傳回不同的值

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

帳戶的主機名稱部分也可以包含萬用字元。如果主機名稱包含 '%''_' 模式字元,或使用網路遮罩表示法,則該帳戶可用於從多個主機連線的用戶端,而 CURRENT_USER() 值不會指示是哪一個。例如,'user2'@'%.example.com' 帳戶可讓 user2example.com 網域中的任何主機連線。如果 user2remote.example.com 連線,則 USER()CURRENT_USER() 會傳回不同的值

mysql> SELECT USER(), CURRENT_USER();
+--------------------------+---------------------+
| USER()                   | CURRENT_USER()      |
+--------------------------+---------------------+
| user2@remote.example.com | user2@%.example.com |
+--------------------------+---------------------+

如果應用程式必須調用 USER() 進行使用者稽核(例如,如果它在觸發器內執行稽核),但也必須能夠將 USER() 值與 user 資料表中的帳戶關聯,則必須避免在 UserHost 欄位中包含萬用字元的帳戶。具體而言,不要允許 User 為空(這會建立匿名使用者帳戶),並且不要允許 Host 值中出現模式字元或網路遮罩表示法。所有帳戶都必須具有非空的 User 值和字面上的 Host 值。

關於先前的範例,''@'localhost''user2'@'%.example.com' 帳戶應該變更為不使用萬用字元。

RENAME USER ''@'localhost' TO 'user1'@'localhost';
RENAME USER 'user2'@'%.example.com' TO 'user2'@'remote.example.com';

如果 user2 必須能夠從 example.com 網域中的多個主機連線,則每個主機都應該有一個獨立的帳戶。

要從 CURRENT_USER()USER() 值中提取使用者名稱或主機名稱部分,請使用 SUBSTRING_INDEX() 函數。

mysql> SELECT SUBSTRING_INDEX(CURRENT_USER(),'@',1);
+---------------------------------------+
| SUBSTRING_INDEX(CURRENT_USER(),'@',1) |
+---------------------------------------+
| user1                                 |
+---------------------------------------+

mysql> SELECT SUBSTRING_INDEX(CURRENT_USER(),'@',-1);
+----------------------------------------+
| SUBSTRING_INDEX(CURRENT_USER(),'@',-1) |
+----------------------------------------+
| localhost                              |
+----------------------------------------+