應用程式可以使用下列準則來執行基於 SQL 的稽核,將資料庫活動連結到 MySQL 帳戶。
MySQL 帳戶對應於 mysql.user
系統資料表中的列。當用戶端成功連線時,伺服器會將用戶端驗證到此表格中的特定列。此列中的 User
和 Host
欄值會唯一識別帳戶,並對應於 SQL 陳述式中寫入帳戶名稱的 '
格式。user_name
'@'host_name
'
用於驗證用戶端的帳戶會決定用戶端擁有的權限。通常,可以呼叫 CURRENT_USER()
函數來確定此用戶端的帳戶。其值是從帳戶的 user
表格列的 User
和 Host
欄中建構的。
但是,在某些情況下,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'
帳戶可讓 user2
從 example.com
網域中的任何主機連線。如果 user2
從 remote.example.com
連線,則 USER()
和 CURRENT_USER()
會傳回不同的值
mysql> SELECT USER(), CURRENT_USER();
+--------------------------+---------------------+
| USER() | CURRENT_USER() |
+--------------------------+---------------------+
| user2@remote.example.com | user2@%.example.com |
+--------------------------+---------------------+
如果應用程式必須調用 USER()
進行使用者稽核(例如,如果它在觸發器內執行稽核),但也必須能夠將 USER()
值與 user
資料表中的帳戶關聯,則必須避免在 User
或 Host
欄位中包含萬用字元的帳戶。具體而言,不要允許 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 |
+----------------------------------------+