仅向用户授予执行存储过程的权限(无选择或插入权限)

3

我想知道是否可能在不授予用户对表的 SELECTINSERT等权限的情况下授予用户 EXECUTE 权限,以运行过程中的表格?

这是用于 Web 应用程序的登录表。MySQL 在 Docker 容器中运行。创建存储过程的 SQL 语句作为 Docker 构建过程的一部分进行复制(运行时,SQL 在 entrypoint.sh 中使用)。Login_db 是在运行容器时创建的(-e 标志)。

我想从下面的代码中删除 GRANT SELECT 行,这样无论发生什么情况,Web 应用程序服务器都无法运行类似于 SELECT * FROM loginsSELECT 查询。

CREATE USER 'logins'@'172.24.0.7' IDENTIFIED BY 'some-password';
GRANT SELECT, INSERT, UPDATE on logins_db.login TO 'logins'@'172.24.0.7';
GRANT EXECUTE ON PROCEDURE logins_db.sp_login16 TO 'logins'@'172.24.0.7';
FLUSH PRIVILEGES;

这并不能解决问题 - 因为表的所有者会暴露相同的权限:

因为表权限而导致GRANT EXECUTE执行存储过程失败

这可能解释了我为什么不能,但表名对我来说有点奇怪(MySQL新手 - 我的印象是mysql.proc是一个系统表,所以不确定它是否适用):

如何授予用户对特定存储过程的执行权限

是不是因为创建该过程时root没有SELECT权限,所以登录用户无法运行它?(因为Docker MySQL运行entrypoint.sh然后才是环境变量)?

该过程代码在这里(我知道,不是最优雅的代码) - 我能否在其中为logins用户GRANT然后REVOKE权限,考虑到DEFINER是root?

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_login16`(
IN p_email VARCHAR(120),
IN p_password VARCHAR(120))
BEGIN
SELECT user_id,user_password FROM login WHERE user_email = p_email;
2个回答

3

是的,您可以通过在声明存储过程时使用sql security definer来实现:

SQL SECURITY特性可以是DEFINER或INVOKER,以指定安全上下文;也就是说,例程是使用例程DEFINER子句中命名的帐户的权限执行还是使用调用它的用户。该帐户必须具有访问与该例程相关联的数据库的权限。默认值是DEFINER。调用例程的用户必须具有EXECUTE权限,如果例程在定义器安全上下文中执行,则定义器账户也必须具有权限。

DEFINER子句指定在具有SQL SECURITY DEFINER特性的例程在例程执行时检查访问权限时要使用的MySQL帐户。

如果在DEFINER子句中给出用户值,它应为“user_name”@“host_name”,CURRENT_USER或CURRENT_USER()指定的MySQL帐户。默认的DEFINER值是执行CREATE PROCEDURE或CREATE FUNCTION语句的用户。这与明确指定DEFINER = CURRENT_USER相同。

总结一下:DEFINER子句中的用户必须拥有对底层表的选择/插入权限,在执行存储过程的用户必须对存储过程具有执行权限。


谢谢你的回答。如果我理解有误,请纠正我,但是这句话似乎表明登录用户需要在登录表上拥有“SELECT”权限才能决定过程成功或失败? - dijksterhuis
很抱歉,我不是很理解你的摘要。但有一件事是确定的,非管理员用户不应该访问mysql数据库中的任何表(名为mysql的数据库),甚至不能进行选择操作。 - Shadow
在你提供的页面下方,有两个示例。我引用的那部分(即MySQL.user表)是在第二个示例之后。它似乎表明一个具有执行权限的用户必须对存储过程将要运行的表具有选择权限? - dijksterhuis
不,示例后的文档明确指出:“该过程的成功或失败取决于调用者是否具有其EXECUTE权限以及'admin'@'localhost'对mysql.user表是否具有SELECT权限。”在示例中,管理员帐户是定义者。 - Shadow
只要定义者有权访问底层表,你就应该没问题。如果不行,那么你描述的问题就不完整。 - Shadow
显示剩余5条评论

1

添加了一个名为ADMIN@localhost的新用户,拥有SELECTINSERTUPDATE权限。然后将ADMIN设置为所有过程的DEFINER,只授予'logins'@'172.24.0.7'执行权限。现在运行得非常完美!

显然,我不能以我尝试的方式使用root。感谢@Shadow指引我正确的方向。

设置管理员用户:

CREATE USER 'admin'@'localhost' IDENTIFIED BY '<password>';
GRANT SELECT, INSERT, UPDATE, DELETE ON db.table_name TO 'admin'@'localhost';
GRANT ALTER ROUTINE, CREATE ROUTINE, EXECUTE ON *.* TO 'admin'@'localhost'; 
FLUSH PRIVILEGES;

定义一个存储过程,使用受限制的管理员用户创建一个条目。
DELIMITER $$
CREATE DEFINER=`admin`@`localhost` PROCEDURE `sp_createTableEntry`(

    IN value_one VARCHAR(120),
    IN value_two VARCHAR(200)
)
BEGIN
    IF ( select exists (select 1 from table_name where column_one = value_one) ) THEN
     
        select 'Column One Exists !!';
     
    ELSE
     
        insert into table_name
        (  
            column_one,
            column_two
        )
        values
        (
            value_one,
            value_two
        );
    END IF ;
END $$
DELIMITER ;

你的链接不再有效。 - Fusion
@Fusion 用实际的 SQL 替换了链接。抱歉,之前将仓库设置为私有的。 - dijksterhuis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接