postgresql特权确保插入只能通过函数完成

时间:2011-10-11 14:23:35

标签: postgresql privileges

假设我有一个只包含名称(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文档中找不到关于授予权限的方法。 有没有办法做到这一点?

3 个答案:

答案 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