【问题标题】:postgresql privileges Ensuring inserts are only done through functionspostgresql 权限 确保插入仅通过函数完成
【发布时间】:2011-10-11 14:23:35
【问题描述】:

假设我有一个仅包含名称(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 的执行权限。 但是如果不这样做,我会因为在函数中使用插入而被拒绝。

我在 postgres 文档中没有找到关于授予权限的方法。 有没有办法做到这一点?

【问题讨论】:

    标签: postgresql privileges


    【解决方案1】:

    您可以使用 SECURITY DEFINER 定义函数。这将允许函数为受限用户运行,就好像他们拥有函数创建者的更高权限(需要能够插入到表中)。

    定义的最后一行如下所示:

    LANGUAGE plpgsql VOLATILE COST 100 SECURITY DEFINER;
    

    【讨论】:

      【解决方案2】:

      这有点简单,但假设正在运行 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 语句频繁的情况,但如果安全性比性能更重要,那就去吧。

      【讨论】:

        【解决方案3】:

        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

        【讨论】:

        • 这是一个常见的(会计)案例,您的选择很少:“允许插入到行项目文件夹中,这样给定的插入集的总金额列为 0。”我想你可以通过约束触发器或打破 1NF 来做到这一点,但第一个快速而肮脏的方法是强制所有插入通过一个函数。这并不意味着不做约束,而是意味着单行约束本身是不够的。
        • @ChrisTravers 已经很长时间了,但我来到谷歌是因为我想解决一些 PG 对继承的限制,比如跨表键的唯一性。 (不分区,儿童需要额外的列。)也是 PG 手册 5.9.1 中的第三个警告。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-01
        • 2015-12-09
        • 2018-01-27
        • 1970-01-01
        • 1970-01-01
        • 2019-03-22
        相关资源
        最近更新 更多