有限用户的“设置密码”

Ben*_*lke 3 mysql permissions mysql-5.6

我正在使用 MySQL 5.6。我想要一个有限的服务用户,它能够创建/修改我的数据库的用户。

现在我的问题是,我可以完全弄清楚我的服务用户需要什么权限来执行所有用户管理任务(创建用户、授予/撤销数据库权限、设置密码)

  1. 如果我给他全局“创建用户”和“重新加载”权限,他就无法使用“设置密码”[= MySQL错误:1044(访问被拒绝)]

  2. 如果我在 'mysql'.'user' 和 'mysql'.'db' 上给他“select”、“insert”、“update”,他就不能使用“设置密码”[= MySQL 错误:1044(访问被拒绝) )]

  3. 如果我在 'mysql'.* 上给他“选择”、“插入”、“更新”,他可以使用“设置密码”

我想了解为什么会发生这种情况,以及如何实现我的方法 1 或 2。我不想使用方法 3。

相当于“设置密码”

UPDATE mysql.user 
SET Password=PASSWORD('newpass') 
WHERE User='bob' 
AND Host='%'; 
Run Code Online (Sandbox Code Playgroud)

...适用于我的特权 1 和 2。

有人可以帮我吗?

Mic*_*bot 5

我看到您提出的问题是,有能力向其他用户授予权限的用户......几乎根据定义,不是“受限”用户。

如果没有权限,您根本无法授予权限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'@'%';
Run Code Online (Sandbox Code Playgroud)

“受限”@“%”用户现在可以通过使用 来更改其他用户的密码,即使他们自己没有这样做的权限CALL mysql.change_password('user','host','password');

该用户本身没有权限,但对进程有执行权限;他们不能直接这样做:

mysql> set password for 'wombat'@'localhost' = PASSWORD('secret');
ERROR 1044 (42000): Access denied for user 'limited'@'%' to database 'mysql'
Run Code Online (Sandbox Code Playgroud)

...但他们可以这样做。请注意,“0 行受影响”不是一个有意义的值。

mysql> call mysql.change_password('wombat','localhost','secret');

Query OK, 0 rows affected (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 带输入参数的字符串连接查询是不可接受的,但该SET PASSWORD语句不接受?位置参数,因此这里别无选择。为了净化输入,我通过在准备好的语句之外提前对其进行加密来处理密码,并将加密的密码连接在那里;我通过从 mysql.user 表中实际选择用户和主机并使用我选择的值(也在准备好的语句之外)来清理用户和主机。如果找不到他们,我们就无法设置他们的密码,因此我们使用 抛出异常SIGNAL。如果找到它们,我们会将获取的值连接到准备好的语句中,并通过此机制对它们进行清理。从理论上讲,mysql.user 表中的错误数据仍然有可能导致对准备好的语句的引用无效,但是如果 mysql.user 表中存在错误数据,那么您会遇到 2 个问题(除此之外还有 1 个问题) 。

  • GRANT EXECUTE如果您删除并重新定义过程,您在过程级别给出的任何显式信息都会从mysql.procs_priv表中消失,因此,如果您对过程进行更改,则必须向受限用户重新授予权限。

  • 您需要 MySQL 5.5+ 才能使该SIGNAL语句有效。在 5.5 以下,您可以用 hack 替换它,例如 CALL mysql.`change_password(): the user/hostprovided`; (注意反引号)这将抛出一个不太漂亮但仍然可用的消息,抱怨反引号中引用的虚假过程名称...不存在。呵呵...ERROR 1305 (42000): PROCEDURE mysql.change_password(): the user/host provided does not exist