sea*_*eas 8 sql security postgresql scripting
我编写PSQL脚本并使用变量(对于psql --variable key = value命令行语法).
这适用于顶级范围,如select*from:key,但我使用脚本创建函数,并在其中需要变量值.
所以,语法就好
create function foo() returns void as
$$
declare
begin
grant select on my_table to group :user;
end;
$$
language plpgsql;
Run Code Online (Sandbox Code Playgroud)
失败于:用户.
据我所知,psql变量是一个普通的宏替换功能,但它不处理函数体.这种情况有没有逃避语法?周围:带有$$的用户有关替换的工作,但psql在$$时失败.
除了独立的宏处理(sed,awk等)之外还有其他方法吗?
PSQL SET变量不会在美元引用的字符串中进行插值.我肯定不知道这一点,但我认为SET在那里打开变量插值没有任何逃避或其他诡计.
有人可能会认为你可以:user在两美元引用的PL/pgSQL之间楔入一个不加引号的方法来获得预期的效果.但这似乎不起作用......我认为语法需要单个字符串而不是连接字符串的表达式.可能会误解为此.
无论如何,那没关系.还有另一种方法(如Pasco所说):编写存储过程以接受PL/pgSQL参数.这就是看起来的样子.
CREATE OR REPLACE FUNCTION foo("user" TEXT) RETURNS void AS
$$
BEGIN
EXECUTE 'GRANT SELECT ON my_table TO GROUP ' || quote_ident(user);
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
关于此功能的说明:
EXECUTEGRANT使用我们的procedure参数在每次调用时生成一个合适的.名为" 执行动态命令 " 的PG手册部分EXECUTE详细说明.user必须加双引号.双引号强制它被解释为标识符.一旦定义了这样的函数,就可以使用插值的PSQL变量来调用它.这是一个大纲.
psql --variable user="'whoever'" --file=myscript.sql.用户名周围需要单引号!select foo(:user);.这就是我们依赖于我们放入的单引号的地方user.虽然这似乎有效,但它让我感到非常犀利.我认为SET变量是用于运行时配置的.携带数据SET似乎很奇怪.
编辑:这是不使用SET变量的具体原因.从联机帮助页:"这些分配是在启动的早期阶段完成的,因此为内部目的保留的变量可能会在以后被覆盖." 如果Postgres决定使用一个名为user(或你选择的任何)的变量,它可能会用你从未想过的东西覆盖你的脚本参数.事实上,psql已经占据USER了自己的位置 - 这只能用于SET区分大小写.这从一开始就差点破坏了!