MySQL 无法使用准备好的语句选择使用自定义函数的视图(权限错误),但直接查询有效
MySQL view using self-defined function cannot be selected (privileges error) with prepared statement but direct query works
在为私人项目构建一个现在稍微复杂的数据库时,我们发现了一个问题,这也可能是一个错误,但我想在这里寻求一些建议,因为也许我的假设是错误的。
序言: 所有视图和功能都创建为 DEFINER = `root`@`localhost` SQL SECURITY DEFINER
。建立连接的最终用户仅限于他可以使用的内容。
对于 FUNCTION(这可能是 MySQL Workbench 行为),SQL SECURITY DEFINER 永远不会被转录到 DDL(?),但是查看 SELECT SECURITY_TYPE FROM information_schema.routines
,肯定是这样写的定义器。
主要问题: 所以当我尝试在 VIEW 的列上使用 FUNCTION 时,问题就出现了,其中 FUNCTION 使用 VIEW 本身,而用户只有 SELECT PRIVILEGES 在第一个提到的 VIEW 上。
如果我直接执行 SELECT,一切都按预期工作,但如果我将 SELECT 放在 PREPAREd 语句中并执行它,我会收到 Error Code: 1356. View 'test.usableview' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
错误。
MySQL 目前使用的服务器是 8.0.22 Windows 10,v8.0.27(最新版本)有同样的问题。
最小示例:
- 作为 root 用户执行以下操作:
CREATE SCHEMA `test`;
USE `test`;
CREATE TABLE IF NOT EXISTS `test`.`basetable_noRights` (
`id` INT NOT NULL AUTO_INCREMENT,
`something` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
INSERT INTO `test`.`basetable_noRights` VALUES (1, 'test');
CREATE TABLE IF NOT EXISTS `test`.`basetable_noRights2` (
`id` INT NOT NULL AUTO_INCREMENT,
`something` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
INSERT INTO `test`.`basetable_noRights2` VALUES (1, 'finally not visible');
CREATE OR REPLACE VIEW `test`.`firstlevelview` AS
SELECT 1 AS id, CONCAT(something, ' 1') AS foo FROM `test`.`basetable_noRights`;
DELIMITER $$
CREATE FUNCTION `user_has_no_rights_function`(i INT) RETURNS VARCHAR(99) CHARSET utf8
READS SQL DATA
begin
SELECT foo INTO @var FROM `test`.`firstlevelview` WHERE id = 1;
return @var;
end$$
DELIMITER ;
CREATE OR REPLACE VIEW `test`.`usableview` AS
SELECT user_has_no_rights_function(id) AS final FROM`test`.`basetable_noRights2` WHERE id = 1;
CREATE OR REPLACE VIEW `test`.`view_without_function` AS
SELECT snd.foo, fst.something FROM `test`.`firstlevelview` snd, `test`.`basetable_noRights` fst;
CREATE USER 'foo'@'%' IDENTIFIED BY 'bar';
GRANT SELECT ON TABLE `test`.`usableview` TO 'foo'@'%';
GRANT SELECT ON TABLE `test`.`view_without_function` TO 'foo'@'%';
FLUSH PRIVILEGES;
- 以新创建的 foo 用户身份登录。比较:
SELECT * FROM view_without_function; -- works
PREPARE asdf FROM "SELECT * FROM view_without_function";
EXECUTE asdf; -- works
SELECT * FROM usableview; -- works
PREPARE asdf2 FROM "SELECT * FROM usableview";
EXECUTE asdf2; -- does not work
顺便说一句,当将函数从 TABLE 而不是 VIEW 更改为 SELECT 时,一切都再次按预期运行。
也许这都是设计使然,但在那种情况下我不理解设计。也许实际上对于准备好的语句需要授予更多权限,我们很幸运直到这里一切正常。
也许这只是一些我不知道的服务器端设置?
我特别期待所有“您需要为基础表授予权限”,尽管我们已经在上面的示例中看到这不是(完全)正确的,因为直接 SELECT 有效并且 MySQL 文档还指出(在我们的例子中)使用了根定义者的特权;)
所描述的行为现在是一个已确认的错误,请参阅https://bugs.mysql.com/bug.php?id=105807。
在为私人项目构建一个现在稍微复杂的数据库时,我们发现了一个问题,这也可能是一个错误,但我想在这里寻求一些建议,因为也许我的假设是错误的。
序言: 所有视图和功能都创建为 DEFINER = `root`@`localhost` SQL SECURITY DEFINER
。建立连接的最终用户仅限于他可以使用的内容。
对于 FUNCTION(这可能是 MySQL Workbench 行为),SQL SECURITY DEFINER 永远不会被转录到 DDL(?),但是查看 SELECT SECURITY_TYPE FROM information_schema.routines
,肯定是这样写的定义器。
主要问题: 所以当我尝试在 VIEW 的列上使用 FUNCTION 时,问题就出现了,其中 FUNCTION 使用 VIEW 本身,而用户只有 SELECT PRIVILEGES 在第一个提到的 VIEW 上。
如果我直接执行 SELECT,一切都按预期工作,但如果我将 SELECT 放在 PREPAREd 语句中并执行它,我会收到 Error Code: 1356. View 'test.usableview' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
错误。
MySQL 目前使用的服务器是 8.0.22 Windows 10,v8.0.27(最新版本)有同样的问题。
最小示例:
- 作为 root 用户执行以下操作:
CREATE SCHEMA `test`;
USE `test`;
CREATE TABLE IF NOT EXISTS `test`.`basetable_noRights` (
`id` INT NOT NULL AUTO_INCREMENT,
`something` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
INSERT INTO `test`.`basetable_noRights` VALUES (1, 'test');
CREATE TABLE IF NOT EXISTS `test`.`basetable_noRights2` (
`id` INT NOT NULL AUTO_INCREMENT,
`something` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
INSERT INTO `test`.`basetable_noRights2` VALUES (1, 'finally not visible');
CREATE OR REPLACE VIEW `test`.`firstlevelview` AS
SELECT 1 AS id, CONCAT(something, ' 1') AS foo FROM `test`.`basetable_noRights`;
DELIMITER $$
CREATE FUNCTION `user_has_no_rights_function`(i INT) RETURNS VARCHAR(99) CHARSET utf8
READS SQL DATA
begin
SELECT foo INTO @var FROM `test`.`firstlevelview` WHERE id = 1;
return @var;
end$$
DELIMITER ;
CREATE OR REPLACE VIEW `test`.`usableview` AS
SELECT user_has_no_rights_function(id) AS final FROM`test`.`basetable_noRights2` WHERE id = 1;
CREATE OR REPLACE VIEW `test`.`view_without_function` AS
SELECT snd.foo, fst.something FROM `test`.`firstlevelview` snd, `test`.`basetable_noRights` fst;
CREATE USER 'foo'@'%' IDENTIFIED BY 'bar';
GRANT SELECT ON TABLE `test`.`usableview` TO 'foo'@'%';
GRANT SELECT ON TABLE `test`.`view_without_function` TO 'foo'@'%';
FLUSH PRIVILEGES;
- 以新创建的 foo 用户身份登录。比较:
SELECT * FROM view_without_function; -- works
PREPARE asdf FROM "SELECT * FROM view_without_function";
EXECUTE asdf; -- works
SELECT * FROM usableview; -- works
PREPARE asdf2 FROM "SELECT * FROM usableview";
EXECUTE asdf2; -- does not work
顺便说一句,当将函数从 TABLE 而不是 VIEW 更改为 SELECT 时,一切都再次按预期运行。 也许这都是设计使然,但在那种情况下我不理解设计。也许实际上对于准备好的语句需要授予更多权限,我们很幸运直到这里一切正常。
也许这只是一些我不知道的服务器端设置?
我特别期待所有“您需要为基础表授予权限”,尽管我们已经在上面的示例中看到这不是(完全)正确的,因为直接 SELECT 有效并且 MySQL 文档还指出(在我们的例子中)使用了根定义者的特权;)
所描述的行为现在是一个已确认的错误,请参阅https://bugs.mysql.com/bug.php?id=105807。