受限使用者的“設置密碼”
我正在使用 MySQL 5.6。我想要一個有限的服務使用者,它能夠創建/修改我的數據庫的使用者。
現在我的問題是我可以完全弄清楚我的服務使用者需要哪些權限來執行所有使用者管理任務(創建使用者、授予/撤銷數據庫權限、設置密碼)
- 如果我給他全域“創建使用者”和“重新載入”權限,他就不能使用“設置密碼”
$$ = MySQL Error: 1044 (Access denied) $$ 2. 如果我在 ‘mysql’.‘user’ 和 ‘mysql’.‘db’ 上給他“select”、“insert”、“update”,他就不能使用“set password”
$$ = MySQL Error: 1044 (Access denied) $$ 3. 如果我在 ‘mysql’.* 上給他“選擇”、“插入”、“更新”,他可以使用“設置密碼”
我想了解為什麼會這樣,以及如何實現我的方法 1 或 2。我不想使用方法 3。
“設置密碼”等價物
UPDATE mysql.user SET Password=PASSWORD('newpass') WHERE User='bob' AND Host='%';
…使用我的特權 1 和 2。
有人可以幫幫我嗎?
我看到您提出的問題是,能夠向其他使用者授予權限的使用者……幾乎按照定義,不是“受限”使用者。
如果沒有特權,您根本無法授予特權
GRANT
,即使如此,您也無法授予您不擁有的特定特權……除非您有權直接操作授權表,在這種情況下,您’也不完全是受限使用者。但是,啊哈,這是您的解決方法。
儲存過程使用定義它們的使用者的憑據或作為明確指定的定義者執行。(您必須將
SUPER
其他人指定為DEFINER
。)任何EXECUTE
對儲存過程具有特權的使用者都可以執行該過程,並且該過程在執行時實質上會提升其特權級別。如果您將您的管理操作包裝在(編寫良好的)過程中,那麼您實際上不必授予受限使用者執行任何操作的權限,而只需執行這些過程。
DELIMITER $$ DROP PROCEDURE IF EXISTS `mysql`.`change_password` $$ -- root@localhost is an example; use an appropriate local user that has the -- permissions that need to be available for the operation to succeed CREATE DEFINER='root'@'localhost' PROCEDURE `mysql`.`change_password` ( IN dirty_user VARCHAR(16), IN dirty_host VARCHAR(40), IN dirty_password VARCHAR(41)) BEGIN DECLARE encrypted_password TINYTEXT DEFAULT PASSWORD(dirty_password); DECLARE clean_user TINYTEXT DEFAULT NULL; DECLARE clean_host TINYTEXT DEFAULT NULL; SELECT user, host FROM mysql.user WHERE user = dirty_user AND host = dirty_host INTO clean_user, clean_host; IF clean_user IS NULL OR clean_host IS NULL THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'user/host provided does not exist'; END IF; SET @_sql = CONCAT_WS('\'','SET PASSWORD FOR ',clean_user,'@',clean_host,' = ',encrypted_password,''); PREPARE stmt FROM @_sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @_sql = NULL; END $$ DELIMITER ; GRANT EXECUTE ON PROCEDURE mysql.change_password TO 'limited'@'%';
’limited’@’%’ 使用者現在可以更改其他使用者的密碼,即使他們沒有自己的權限,使用
CALL mysql.change_password('user','host','password');
.該使用者自己沒有權限,但在 proc 上有執行;他們不能直接這樣做:
mysql> set password for 'wombat'@'localhost' = PASSWORD('secret'); ERROR 1044 (42000): Access denied for user 'limited'@'%' to database 'mysql'
…但他們可以這樣做。請注意,“0 行受影響”不是一個有意義的值。
mysql> call mysql.change_password('wombat','localhost','secret'); Query OK, 0 rows affected (0.00 sec)
筆記:
- 帶有輸入參數的字元串連接查詢是不可接受的,但是該
SET PASSWORD
語句不接受?
位置參數,所以這裡沒有選擇。為了清理輸入,我通過預先在準備好的語句之外對密碼進行加密來處理密碼,並在那裡連接加密的密碼;我已經通過從 mysql.user 表中實際選擇它們並使用我選擇的值(也在準備好的語句之外)對使用者和主機進行了清理。如果找不到,我們就不能設置他們的密碼,所以我們使用拋出異常SIGNAL
. 如果找到它們,我們將獲取的值連接到準備好的語句中,並通過這種機制對它們進行清理。理論上 mysql.user 表中的不良數據仍然可能導致prepared statement的引用無效,但是如果您在 mysql.user 表中存在不良數據,那麼您有2個問題(除此之外還有1個問題) .GRANT EXECUTE
如果您刪除並重新定義過程,您在過程級別給出的任何顯式都會從mysql.procs_priv
表中消失,因此如果您對過程進行更改,則必須將權限重新授予受限使用者。- 您需要 MySQL 5.5+ 才能使
SIGNAL
語句有效。在 5.5 以下,您可以將其替換為 hack,例如 CALL mysql.change_password(): the user/host provided
; (注意反引號)這將拋出一個不太漂亮但仍然有用的消息,抱怨反引號中引用的虛假過程名稱……不存在。呵呵……ERROR 1305 (42000): PROCEDURE mysql.change_password(): the user/host provided does not exist