安全定义器不在内部工作而不是触发器?

时间:2018-04-24 13:10:03

标签: postgresql plpgsql

我有一个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;

1 个答案:

答案 0 :(得分:2)

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

请参阅ri_PerformCheck中的src/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并使用atableON UPDATE OR DELETE CASCADE添加外键。用户Abtable无权限。

  • 用户A尝试更新或删除atable中与btable级联但未通过“权限被拒绝”错误的行。

我个人不确定目前的行为是否良好,但我可以看出A'无法修改她所拥有的表格会令人感到意外。