【问题标题】:Security definer not working inside instead of trigger?安全定义器不在内部而不是触发器中工作?
【发布时间】:2018-04-24 13:10:02
【问题描述】:

我有一个 PostgreSQL 9.5 数据库:

  • 存储字段可能值的表 test.domain(int id, text value)。这些数据是动态的。
  • 一个表 test.table(id int, domainn text),其中 domainn 字段引用了 test.domain 表。
  • 一个视图 test.view_domain,它是 test.domain 的一个视图。

我已经使用视图上的安全定义器选项定义了 INSTEAD 触发器。此触发器更新表 test.domain。问题是,尽管这个触发器是作为用户“system”执行的,但表 test.table 上的引用更新是由调用者用户执行的。

这是一个示例,如果作为 postgres 执行,我希望得到“用户系统”作为错误而不是“用户 postgres”

drop schema IF EXISTS test  cascade;
create schema test;


create function test.modified() returns trigger as
$$
BEGIN
    raise exception 'user %', ' '||current_user;
END
$$
language plpgsql;

set role system;

create function test.insert_with_system() returns trigger as
$$
DECLARE
 valor text;
BEGIN

    --raise exception 'user %', ' '||current_user;
    update test.domain set value =  ''||new.value where id =  new.id;

END
$$ language plpgsql security definer;

reset role;

CREATE table test.domain(

id int primary key,
value text unique
);

create view test.domain_view as select * from test.domain;

create table test.table(
id int primary key,
domainn text
);

alter table test.table add foreign key (domainn)
   references test.domain(value) on delete restrict on update cascade;

create trigger test_trigger before insert or update or delete on test.table
   for each row execute procedure test.modified();

create trigger instead_ins INSTEAD OF update or delete on test.domain_view 
   for each row execute procedure test.insert_with_system();


insert into test.domain(id, value) values(1,'one');

alter table test.table  DISABLE TRIGGER all;
insert into test.table(id, domainn) values (0,'one');
alter table test.table enable TRIGGER all;

update test.domain_view set value = 'two';
select * from test.table;

【问题讨论】:

    标签: postgresql plpgsql


    【解决方案1】:

    级联更新始终在引用表所有者的安全上下文中运行(在您的示例中为test.table)。

    ri_PerformChecksrc/backend/utils/adt/ri_triggers.c

    /*
     * Use the query type code to determine whether the query is run against
     * the PK or FK table; we'll do the check as that table's owner
     */
    if (qkey->constr_queryno <= RI_PLAN_LAST_ON_PK)
        query_rel = pk_rel;
    else
        query_rel = fk_rel;
    
    ...
    
    /* Switch to proper UID to perform check as */
    GetUserIdAndSecContext(&save_userid, &save_sec_context);
    SetUserIdAndSecContext(RelationGetForm(query_rel)->relowner,
                           save_sec_context | SECURITY_LOCAL_USERID_CHANGE |
                           SECURITY_NOFORCE_RLS);
    

    我试图追踪代码的起源,并且该行为似乎起源于提交465cf168eb6151275016486fe2d2c629fed967ca

    在黑客档案中搜索相关讨论,发现this

    因此,据我所知,该行为试图避免以下情况:

    • 用户 A 拥有 atable 并将该表上的 REFERENCES 授予用户 B

    • 用户B 拥有btable 并使用ON UPDATE OR DELETE CASCADE 将外键添加到atable。用户A 没有btable 的权限。

    • 用户 A 尝试更新或删除 atable 中的一行,该行将级联到 btable 并失败并出现“权限被拒绝”错误。

    我个人不确定目前的行为是否良好,但我可以看到,A' 不能修改她拥有的表会令人惊讶。

    【讨论】:

      猜你喜欢
      • 2017-10-06
      • 2013-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-20
      • 2018-01-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多