應用程式可以使用下列準則來執行基於 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 |
+----------------------------------------+