【问题标题】:multi table auditing trigger function多表审计触发功能
【发布时间】:2016-02-02 21:01:47
【问题描述】:

我想保留我的表格的所有更改。我有一个为每个表创建触发器的工作解决方案,但复制代码 foreach 表似乎很愚蠢。有没有办法创建一个这样的触发函数?

我的工作表触发器示例(包括表定义):

CREATE TABLE departments (
    id                  bigserial Primary Key,
    name                varchar not null,
    created             bigint not null default date_part('epoch', NOW()),
    created_by          bigint references Employees (id) not null
);
create table Departments_hist ("action" varchar not null, change_date bigint not null, rev bigserial not null, like Departments);
CREATE OR REPLACE FUNCTION add_to_history_Departments() RETURNS TRIGGER AS $$
BEGIN
IF(TG_OP='INSERT' OR TG_OP='UPDATE') THEN
    INSERT INTO Departments_hist values (TG_OP,date_part('epoch', NOW()),DEFAULT,NEW.*);
END IF;
IF (TG_OP='DELETE') THEN
    INSERT INTO Departments_hist values (TG_OP,date_part('epoch', NOW()),DEFAULT,OLD.*);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_history_Departments AFTER INSERT OR UPDATE OR DELETE ON Departments FOR EACH ROW EXECUTE PROCEDURE add_to_history_Departments();

我尝试通过将 '_hist' 连接到 TG_TABLE_NAME 来使其成为多表:

CREATE OR REPLACE FUNCTION add_to_hist_table() RETURNS TRIGGER AS $$
DECLARE
    histTable text :=TG_TABLE_NAME || '_hist';
BEGIN
    IF (TG_OP='INSERT' OR TG_OP='UPDATE') THEN
        INSERT INTO histTable values (TG_OP,date_part('epoch', NOW()),DEFAULT,NEW.*);
    ELSIF TG_OP='DELETE' THEN
        INSERT INTO histTable values (TG_OP,date_part('epoch', NOW()),DEFAULT,OLD.*);
    END IF;
    RETURN null; --ignored since it is an AFTER triggger.
END;
$$ LANGUAGE plpgsql;

但我得到一个错误:

ERROR:  syntax error at or near "$1"
LINE 1: INSERT INTO  $1  values ( $2 ,date_part('epoch', NOW()),DEFA...
                     ^
QUERY:  INSERT INTO  $1  values ( $2 ,date_part('epoch', NOW()),DEFAULT, $3 .*)
CONTEXT:  SQL statement in PL/PgSQL function "add_to_hist_table" near line 5

我猜这是变量替换的问题 (http://www.postgresql.org/docs/8.4/static/plpgsql-implementation.html)。

如何实现这个功能?

PS。我正在使用 postgresql 8.4,但可能很快会升级到 9.3。

【问题讨论】:

    标签: postgresql triggers plpgsql


    【解决方案1】:

    我找到了解决这个“相关问题”https://stackoverflow.com/a/1997417/844731

    我没想过对 NEW 和 OLD 进行“执行使用”。所以现在一个可行的解决方案是:

    CREATE OR REPLACE FUNCTION add_to_hist_table() RETURNS TRIGGER AS $$
    BEGIN
    IF (TG_OP='INSERT' OR TG_OP='UPDATE') THEN
        execute 'INSERT INTO '|| TG_TABLE_NAME ||'_hist values (''' || TG_OP || ''',date_part(''epoch'', NOW()),DEFAULT,$1.*)' using NEW;
    ELSIF TG_OP='DELETE' THEN
        execute 'INSERT INTO '|| TG_TABLE_NAME ||'_hist values (''' || TG_OP || ''',date_part(''epoch'', NOW()),DEFAULT,$1.*)'  using OLD;
    END IF;
    RETURN null; --ignored since it is an AFTER triggger.
    END;
    $$ LANGUAGE plpgsql;
    

    【讨论】:

    • 注意 - 这个例子容易受到 SQL 注入的攻击。任何参数都是动态查询字符串,必须进行清理(转义)。
    • 嗨@PavelStehule。它如何或在哪里是可变化的? (这是一个触发器,我不使用任何尚未被 postgres 解释的用户输入变量)
    • @PavelStehule 你能指出它在哪里是可破坏的或展示一个更好的解决方案吗?谢谢:-)
    【解决方案2】:

    @Pascal_dher,有人可以使用包含攻击者代码的名称创建表。由于 Postgresql 这可能不会做一些非常糟糕的,只有失败的查询。但是,如果您的触发器会更复杂,那么影响可能会更糟。

    【讨论】:

    • 但是如果他们可以在利用之前创建表,他们就不能做所有事情吗?使用 quote_ident (tg_table_name||'_hist') 和 quote_literal(tg_op) 会修复潜在的 sql 注入吗?
    猜你喜欢
    • 2021-09-05
    • 2014-04-14
    • 2014-04-19
    • 2021-06-05
    • 1970-01-01
    • 2016-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多