MySQL 伺服器會使用驗證外掛程式來驗證用戶端連線。驗證給定連線的外掛程式可能會要求將連線的 (外部) 使用者視為不同的使用者,以便進行權限檢查。這可讓外部使用者成為第二個使用者的代理;也就是說,假設第二個使用者的權限。
外部使用者是 「代理使用者」(可以模擬或成為另一個使用者的使用者)。
第二個使用者是 「被代理使用者」(其身分和權限可以由代理使用者假設的使用者)。
本節說明代理使用者功能的工作方式。如需有關驗證外掛程式的一般資訊,請參閱章節 8.2.17,「可插拔驗證」。如需有關特定外掛程式的資訊,請參閱章節 8.4.1,「驗證外掛程式」。如需有關撰寫支援代理使用者的驗證外掛程式的資訊,請參閱在驗證外掛程式中實作代理使用者支援。
透過代理獲得的一個管理好處是,DBA 可以設定一個具有一組權限的單一帳戶,然後讓多個代理使用者擁有這些權限,而無需將權限個別指派給每個使用者。作為代理使用者的替代方案,DBA 可能會發現角色提供了一種將使用者對應到特定具名權限集合的適當方式。可以將每個使用者授予一個指定的單一角色,以有效地授予適當的權限集合。請參閱章節 8.2.10,「使用角色」。
若要使特定驗證外掛程式發生代理,必須滿足這些條件
代理功能必須被支援,無論是透過外掛程式本身,或是由 MySQL 伺服器代表外掛程式執行。在後者的情況下,可能需要明確啟用伺服器支援;請參閱伺服器對代理使用者映射的支援。
外部代理使用者的帳戶必須設定為由外掛程式進行驗證。使用
CREATE USER
陳述式將帳戶與驗證外掛程式建立關聯,或使用ALTER USER
變更其外掛程式。被代理使用者的帳戶必須存在,並且被授予代理使用者所要承擔的權限。請使用
CREATE USER
和GRANT
陳述式來實現。通常,被代理使用者會被設定為只能在代理情境中使用,而不能直接登入。
為了使連線到代理帳戶的用戶端被視為代理使用者,驗證外掛程式必須傳回與用戶端使用者名稱不同的使用者名稱,以指示定義代理使用者所要承擔的權限的被代理帳戶的使用者名稱。
或者,對於由伺服器提供代理映射的外掛程式,被代理使用者是從代理使用者持有的
PROXY
權限中決定的。
代理機制僅允許將外部用戶端使用者名稱映射到被代理的使用者名稱。沒有提供主機名稱映射的功能。
當用戶端連線到伺服器時,伺服器會根據用戶端程式傳遞的使用者名稱和用戶端連線的主機來決定正確的帳戶。
如果該帳戶是代理帳戶,伺服器會嘗試透過尋找符合驗證外掛程式傳回的使用者名稱和代理帳戶主機名稱的被代理帳戶,來決定適當的被代理帳戶。被代理帳戶中的主機名稱會被忽略。
考慮以下帳戶定義
-- create proxy account
CREATE USER 'employee_ext'@'localhost'
IDENTIFIED WITH my_auth_plugin
AS 'my_auth_string';
-- create proxied account and grant its privileges;
-- use mysql_no_login plugin to prevent direct login
CREATE USER 'employee'@'localhost'
IDENTIFIED WITH mysql_no_login;
GRANT ALL
ON employees.*
TO 'employee'@'localhost';
-- grant to proxy account the
-- PROXY privilege for proxied account
GRANT PROXY
ON 'employee'@'localhost'
TO 'employee_ext'@'localhost';
當用戶端從本機主機以 employee_ext
的身分連線時,MySQL 會使用名為 my_auth_plugin
的外掛程式來執行驗證。假設 my_auth_plugin
根據 '
的內容,或許還會查詢某些外部驗證系統,向伺服器傳回 my_auth_string
'employee
的使用者名稱。employee
名稱與 employee_ext
不同,因此傳回 employee
作為請求伺服器將 employee_ext
外部使用者,為了權限檢查的目的,視為 employee
本機使用者。
在這種情況下,employee_ext
是代理使用者,而 employee
是被代理使用者。
伺服器會檢查 employee_ext
使用者是否可以為 employee
進行代理驗證,方法是檢查 employee_ext
(代理使用者) 是否擁有針對 employee
(被代理使用者) 的 PROXY
權限。如果此權限尚未被授予,則會發生錯誤。否則,employee_ext
會承擔 employee
的權限。伺服器會根據授予 employee
的權限來檢查用戶端連線階段中由 employee_ext
執行的陳述式。在這種情況下,employee_ext
可以存取 employees
資料庫中的表格。
被代理帳戶 employee
使用 mysql_no_login
驗證外掛程式來防止用戶端直接使用該帳戶登入。(這假設外掛程式已安裝。如需說明,請參閱章節 8.4.1.8,「無登入可插拔驗證」)。如需保護被代理帳戶免於直接使用的其他方法,請參閱防止直接登入被代理帳戶。
當發生代理時,可以使用 USER()
和 CURRENT_USER()
函式來查看連線使用者 (代理使用者) 與目前連線階段套用其權限的帳戶 (被代理使用者) 之間的差異。對於剛才描述的範例,這些函式會傳回以下值
mysql> SELECT USER(), CURRENT_USER();
+------------------------+--------------------+
| USER() | CURRENT_USER() |
+------------------------+--------------------+
| employee_ext@localhost | employee@localhost |
+------------------------+--------------------+
在建立代理使用者帳戶的 CREATE USER
陳述式中,指定支援代理的驗證外掛程式的 IDENTIFIED WITH
子句可以選擇性地接上 AS '
子句,該子句指定伺服器在使用者連線時傳遞給外掛程式的字串。如果存在,該字串會提供資訊來幫助外掛程式決定如何將代理 (外部) 用戶端使用者名稱映射到被代理的使用者名稱。是否需要 auth_string
'AS
子句由每個外掛程式決定。如果是這樣,驗證字串的格式取決於外掛程式打算如何使用它。有關其接受的驗證字串值資訊,請查閱特定外掛程式的文件。
被代理帳戶通常僅用於透過代理帳戶的方式使用。也就是說,用戶端使用代理帳戶連線,然後被映射到並承擔適當的被代理使用者的權限。
有多種方法可以確保無法直接使用被代理帳戶
將該帳戶與
mysql_no_login
驗證外掛程式建立關聯。在這種情況下,該帳戶在任何情況下都不能用於直接登入。這假設外掛程式已安裝。如需說明,請參閱章節 8.4.1.8,「無登入可插拔驗證」。在建立帳戶時包含
ACCOUNT LOCK
選項。請參閱章節 15.7.1.3,「CREATE USER 陳述式」。使用此方法,還請包含密碼,以便如果稍後解除鎖定帳戶,則無法在沒有密碼的情況下存取該帳戶。(如果啟用了validate_password
元件,即使帳戶被鎖定,也不允許建立沒有密碼的帳戶。請參閱章節 8.4.3,「密碼驗證元件」。)使用密碼建立帳戶,但不要告訴其他人密碼。如果您不讓任何人知道該帳戶的密碼,用戶端將無法使用它直接連線到 MySQL 伺服器。
需要 PROXY
權限才能讓外部使用者以另一個使用者的身分連線並擁有其權限。若要授予此權限,請使用 GRANT
陳述式。例如
GRANT PROXY ON 'proxied_user' TO 'proxy_user';
該陳述式會在 mysql.proxies_priv
授予表中建立一列。
在連線時,proxy_user
必須代表有效的外部驗證 MySQL 使用者,而 proxied_user
必須代表有效的本機驗證使用者。否則,連線嘗試會失敗。
對應的 REVOKE
語法為
REVOKE PROXY ON 'proxied_user' FROM 'proxy_user';
MySQL GRANT
和 REVOKE
語法延伸功能可照常運作。範例
-- grant PROXY to multiple accounts
GRANT PROXY ON 'a' TO 'b', 'c', 'd';
-- revoke PROXY from multiple accounts
REVOKE PROXY ON 'a' FROM 'b', 'c', 'd';
-- grant PROXY to an account and enable the account to grant
-- PROXY to the proxied account
GRANT PROXY ON 'a' TO 'd' WITH GRANT OPTION;
-- grant PROXY to default proxy account
GRANT PROXY ON 'a' TO ''@'';
在以下情況下可以授予 PROXY
權限
透過針對
proxied_user
具有GRANT PROXY ... WITH GRANT OPTION
的使用者。透過
proxied_user
針對自身:USER()
的值必須與CURRENT_USER()
和proxied_user
完全符合,包括帳戶名稱的使用者名稱和主機名稱部分。
在 MySQL 安裝期間建立的初始 root
帳戶具有針對 ''@''
,也就是所有使用者和所有主機的 PROXY ... WITH GRANT OPTION
權限。這使得 root
能夠設定代理使用者,以及將設定代理使用者的權限委派給其他帳戶。例如,root
可以執行以下操作
CREATE USER 'admin'@'localhost'
IDENTIFIED BY 'admin_password';
GRANT PROXY
ON ''@''
TO 'admin'@'localhost'
WITH GRANT OPTION;
這些陳述式會建立一個可以管理所有 GRANT PROXY
映射的 admin
使用者。例如,admin
可以執行以下操作
GRANT PROXY ON sally TO joe;
若要指定某些或所有使用者應使用給定的驗證外掛程式連線,請建立一個使用者名稱和主機名稱皆為空值的「空白」MySQL 帳戶 (''@''
),將其與該外掛程式建立關聯,並讓外掛程式傳回真實的驗證使用者名稱 (如果與空白使用者不同)。假設存在一個名為 ldap_auth
的外掛程式,該外掛程式實作 LDAP 驗證並將連線使用者映射到開發人員或管理員帳戶。若要設定使用者映射到這些帳戶的代理,請使用以下陳述式
-- create default proxy account
CREATE USER ''@''
IDENTIFIED WITH ldap_auth
AS 'O=Oracle, OU=MySQL';
-- create proxied accounts; use
-- mysql_no_login plugin to prevent direct login
CREATE USER 'developer'@'localhost'
IDENTIFIED WITH mysql_no_login;
CREATE USER 'manager'@'localhost'
IDENTIFIED WITH mysql_no_login;
-- grant to default proxy account the
-- PROXY privilege for proxied accounts
GRANT PROXY
ON 'manager'@'localhost'
TO ''@'';
GRANT PROXY
ON 'developer'@'localhost'
TO ''@'';
現在假設用戶端按如下方式連線
$> mysql --user=myuser --password ...
Enter password: myuser_password
伺服器找不到定義為 MySQL 使用者的 myuser
,但由於有一個與用戶端使用者名稱和主機名稱相符的空白使用者帳戶 (''@''
),伺服器會針對該帳戶驗證用戶端。伺服器會叫用 ldap_auth
驗證外掛程式,並將 myuser
和 myuser_password
作為使用者名稱和密碼傳遞給它。
如果 ldap_auth
外掛程式在 LDAP 目錄中發現 myuser_password
不是 myuser
的正確密碼,則驗證會失敗,伺服器會拒絕連線。
如果密碼正確,且 ldap_auth
發現 myuser
是開發人員,則它會向 MySQL 伺服器傳回使用者名稱 developer
,而不是 myuser
。傳回與 myuser
的用戶端使用者名稱不同的使用者名稱,會向伺服器發出訊號,表示它應將 myuser
視為代理。伺服器會驗證 ''@''
是否可以驗證為 developer
(因為 ''@''
具有這樣做的 PROXY
權限),並接受連線。連線階段會以 myuser
擁有 developer
被代理使用者的權限繼續進行。(這些權限應由 DBA 使用 GRANT
陳述式設定,此處未顯示。) USER()
和 CURRENT_USER()
函式會傳回以下值
mysql> SELECT USER(), CURRENT_USER();
+------------------+---------------------+
| USER() | CURRENT_USER() |
+------------------+---------------------+
| myuser@localhost | developer@localhost |
+------------------+---------------------+
如果外掛程式在 LDAP 目錄中發現 myuser
是管理員,則會回傳 manager
作為使用者名稱,並且會繼續執行階段,myuser
擁有 manager
代理使用者的權限。
mysql> SELECT USER(), CURRENT_USER();
+------------------+-------------------+
| USER() | CURRENT_USER() |
+------------------+-------------------+
| myuser@localhost | manager@localhost |
+------------------+-------------------+
為簡化起見,外部驗證不能是多層次的:在前面的範例中,無論是 developer
還是 manager
的憑證都不會被考慮。但是,如果客戶端嘗試直接以 developer
或 manager
帳戶連線和驗證,則這些憑證仍然會被使用,這就是為什麼這些代理帳戶應受到保護,避免直接登入的原因(請參閱防止直接登入代理帳戶)。
如果您打算建立預設代理使用者,請檢查是否有其他現有的「符合任何使用者」帳戶優先於預設代理使用者,因為它們可能會阻止該使用者如預期般運作。
在前面的討論中,預設代理使用者帳戶的主機部分為 ''
,這符合任何主機。如果您設定預設代理使用者,請務必檢查是否存在使用者部分相同且主機部分為 '%'
的非代理帳戶,因為 '%'
也符合任何主機,但根據伺服器內部用來排序帳戶列的規則,它優先於 ''
(請參閱第 8.2.6 節,「存取控制,階段 1:連線驗證」)。
假設 MySQL 安裝包含以下兩個帳戶
-- create default proxy account
CREATE USER ''@''
IDENTIFIED WITH some_plugin
AS 'some_auth_string';
-- create anonymous account
CREATE USER ''@'%'
IDENTIFIED BY 'anon_user_password';
第一個帳戶(''@''
)預期作為預設代理使用者,用於驗證不符合更特定帳戶的使用者的連線。第二個帳戶(''@'%'
)是一個匿名使用者帳戶,建立該帳戶可能是為了讓沒有自己帳戶的使用者匿名連線。
這兩個帳戶都有相同的使用者部分(''
),符合任何使用者。而且每個帳戶都有符合任何主機的主機部分。儘管如此,在連線嘗試中,帳戶比對仍有優先順序,因為比對規則會將主機為 '%'
的優先於 ''
。對於不符合任何更特定帳戶的帳戶,伺服器會嘗試根據 ''@'%'
(匿名使用者)而不是 ''@''
(預設代理使用者)驗證它們。因此,永遠不會使用預設代理帳戶。
為避免此問題,請使用以下其中一種策略
移除匿名帳戶,使其不會與預設代理使用者衝突。
使用更特定的預設代理使用者,使其優先於匿名使用者。例如,若要僅允許
localhost
代理連線,請使用''@'localhost'
CREATE USER ''@'localhost' IDENTIFIED WITH some_plugin AS 'some_auth_string';
此外,修改任何
GRANT PROXY
陳述式,以指定''@'localhost'
而不是''@''
作為代理使用者。請注意,此策略會阻止來自
localhost
的匿名使用者連線。使用具名的預設帳戶,而不是匿名的預設帳戶。如需此技術的範例,請查閱使用
authentication_windows
外掛程式的說明。請參閱第 8.4.1.5 節,「Windows 可插拔驗證」。建立多個代理使用者,一個用於本機連線,另一個用於「其他所有」(遠端連線)。當本機使用者應具有與遠端使用者不同的權限時,此功能特別有用。
建立代理使用者
-- create proxy user for local connections CREATE USER ''@'localhost' IDENTIFIED WITH some_plugin AS 'some_auth_string'; -- create proxy user for remote connections CREATE USER ''@'%' IDENTIFIED WITH some_plugin AS 'some_auth_string';
建立代理的使用者
-- create proxied user for local connections CREATE USER 'developer'@'localhost' IDENTIFIED WITH mysql_no_login; -- create proxied user for remote connections CREATE USER 'developer'@'%' IDENTIFIED WITH mysql_no_login;
授予每個代理帳戶對應代理帳戶的
PROXY
權限GRANT PROXY ON 'developer'@'localhost' TO ''@'localhost'; GRANT PROXY ON 'developer'@'%' TO ''@'%';
最後,授予本機和遠端代理使用者適當的權限(未顯示)。
假設
some_plugin
/'
組合導致some_auth_string
'some_plugin
將客戶端使用者名稱對應到developer
。本機連線符合''@'localhost'
代理使用者,這會對應到'developer'@'localhost'
代理使用者。遠端連線符合''@'%'
代理使用者,這會對應到'developer'@'%'
代理使用者。
某些驗證外掛程式會自行實作代理使用者對應(例如,PAM 和 Windows 驗證外掛程式)。其他驗證外掛程式預設不支援代理使用者。sha256_password
可以要求 MySQL 伺服器本身根據授與的代理權限來對應代理使用者。如果啟用 check_proxy_users
系統變數,則伺服器會為提出此要求的任何驗證外掛程式執行代理使用者對應
預設情況下,
check_proxy_users
處於停用狀態,因此即使驗證外掛程式要求伺服器支援代理使用者,伺服器也不會執行任何代理使用者對應。如果啟用
check_proxy_users
,可能還需要啟用外掛程式特定的系統變數,才能利用伺服器代理使用者對應支援。對於sha256_password
外掛程式,請啟用sha256_password_proxy_users
。
例如,若要啟用上述所有功能,請在 my.cnf
檔案中使用下列幾行啟動伺服器
[mysqld]
check_proxy_users=ON
sha256_password_proxy_users=ON
假設已啟用相關的系統變數,請使用 CREATE USER
正常建立代理使用者,然後將其 PROXY
權限授與給另一個將被視為代理使用者的單一帳戶。當伺服器收到代理使用者的成功連線要求時,它會發現該使用者具有 PROXY
權限,並使用該權限來判斷正確的代理使用者。
-- create proxy account
CREATE USER 'proxy_user'@'localhost'
IDENTIFIED WITH sha256_password
BY 'password';
-- create proxied account and grant its privileges;
-- use mysql_no_login plugin to prevent direct login
CREATE USER 'proxied_user'@'localhost'
IDENTIFIED WITH mysql_no_login;
-- grant privileges to proxied account
GRANT ...
ON ...
TO 'proxied_user'@'localhost';
-- grant to proxy account the
-- PROXY privilege for proxied account
GRANT PROXY
ON 'proxied_user'@'localhost'
TO 'proxy_user'@'localhost';
若要使用代理帳戶,請使用其名稱和密碼連線到伺服器
$> mysql -u proxy_user -p
Enter password: (enter proxy_user password here)
驗證成功,伺服器發現 proxy_user
具有 proxied_user
的 PROXY
權限,並且會繼續執行階段,proxy_user
擁有 proxied_user
的權限。
伺服器執行的代理使用者對應受限於以下限制
即使授與了相關的
PROXY
權限,伺服器也不會代理到匿名使用者或從匿名使用者代理。當單一帳戶被授與多個代理帳戶的代理權限時,伺服器代理使用者對應是不確定的。因此,不建議將多個代理帳戶的代理權限授與給單一帳戶。
兩個系統變數可協助追蹤代理登入程序
proxy_user
:如果未使用代理,則此值為NULL
。否則,它會指出代理使用者帳戶。例如,如果客戶端透過''@''
代理帳戶進行驗證,則會將此變數設定如下mysql> SELECT @@proxy_user; +--------------+ | @@proxy_user | +--------------+ | ''@'' | +--------------+
external_user
:有時,驗證外掛程式可能會使用外部使用者向 MySQL 伺服器進行驗證。例如,當使用 Windows 原生驗證時,使用 Windows API 進行驗證的外掛程式不需要傳遞給它的登入 ID。但是,它仍然使用 Windows 使用者 ID 進行驗證。外掛程式可以使用external_user
唯讀階段變數,將此外部使用者 ID(或其前 512 個 UTF-8 位元組)傳回伺服器。如果外掛程式未設定此變數,則其值為NULL
。