假设我有一个只包含名称(varchar)和用户客户端的表人员。
我希望客户端插入人员的唯一方法是通过以下功能:
CREATE OR REPLACE FUNCTION add_a_person(a_name varying character)
RETURNS void AS
$BODY$
BEGIN
INSERT INTO persons VALUES(a_name);
END;
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;
因此,我不想授予人员客户端插入权限,只为add_a_person授予执行权限。 但是如果没有这样做,我会因为在函数中使用insert而获得权限被拒绝。
我在postgres文档中找不到关于授予权限的方法。 有没有办法做到这一点?
答案 0 :(得分:5)
您可以使用SECURITY DEFINER定义该功能。这将允许该函数为受限用户运行,就好像他们具有该函数创建者的更高权限(需要能够插入表中)。
定义的最后一行如下所示:
LANGUAGE plpgsql VOLATILE COST 100 SECURITY DEFINER;
答案 1 :(得分:1)
这有点过于简单,但假设正在运行9.2
或更高版本,这是一个如何检查执行插入的单个允许函数的示例:
CREATE TABLE my_table (col1 text, col2 integer, col3 timestamp);
CREATE FUNCTION my_table_insert_function(col1 text, col2 integer) RETURNS integer AS $$
BEGIN
INSERT INTO my_table VALUES (col1, col2, current_timestamp);
RETURN 1;
END $$ LANGUAGE plpgsql;
CREATE FUNCTION my_table_insert_trigger_function() RETURNS trigger AS $$
DECLARE
stack text;
fn integer;
BEGIN
RAISE EXCEPTION 'secured';
EXCEPTION WHEN OTHERS THEN
BEGIN
GET STACKED DIAGNOSTICS stack = PG_EXCEPTION_CONTEXT;
fn := position('my_table_insert_function' in stack);
IF (fn <= 0) THEN
RAISE EXCEPTION 'Expecting insert from my_table_insert_function'
USING HINT = 'Use function to insert data';
END IF;
RETURN new;
END;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER my_table_insert_trigger BEFORE INSERT ON my_table
FOR EACH ROW EXECUTE PROCEDURE my_table_insert_trigger_function();
快速使用示例:
INSERT INTO my_table VALUES ('test one', 1, current_timestamp); -- FAILS
SELECT my_table_insert_function('test one', 1); -- SUCCEEDS
如果您希望代码更加健壮,安全等,您将需要更详细地查看堆栈。当然,可以检查多个功能,但需要更多工作。将堆栈拆分成多行并解析它可能会非常复杂,所以如果事情变得更复杂,你可能会想要一些辅助函数。
这只是一个概念证明,但它符合它的要求。考虑到使用异常处理和堆栈检查,我希望这段代码相当慢,所以不要在应用程序的性能关键部分使用它。它不太适合DML
语句频繁出现的情况,但如果安全性比性能更重要,那就去做吧。
答案 2 :(得分:0)
Matthew的回答是正确的,因为SECURITY DEFINER将允许该功能以不同用户的权限运行。有关此文档的文档位于http://www.postgresql.org/docs/9.1/static/sql-createfunction.html
为什么要尝试以这种方式实现安全性?如果你想在插入上强制执行一些逻辑,那么我强烈建议你使用约束。 http://www.postgresql.org/docs/9.1/static/ddl-constraints.html
如果你想要比在约束中合理实现的逻辑水平更高的逻辑,我建议考虑在表示层和数据存储层之间构建业务逻辑层。您会发现可扩展性几乎立即需要它。
如果您的目标是防御SQL注入,那么您已经找到了可行的方法,但这将为您创造大量工作。更糟糕的是,它会导致大量真正无意识的代码,这些代码必须在架构更改中保持同步。如果你想做任何敏捷的事情,这是非常粗糙的。相反,请考虑使用利用PREPARE / EXECUTE的编程框架,此时几乎所有这些都是。 http://www.postgresql.org/docs/9.0/static/sql-prepare.html