PostgreSQL行级策略实验
行级策略实验
创建测试表并插入数据:
TEST=# create table test(id serial primary key, user_name varchar(32), crt_time timestamp default now());
CREATE TABLE
TEST=# insert into test(user_name) values('U1');
INSERT 0 1
TEST=# insert into test(user_name) values('U2');
INSERT 0 1
TEST=# insert into test(user_name) values('U3');
INSERT 0 1
TEST=# insert into test(user_name) values('U1');
INSERT 0 1
TEST=# insert into test(user_name) values('U2');
INSERT 0 1
TEST=# insert into test(user_name) values('U3');
INSERT 0 1
创建用户:
TEST=# create user U1 password 'u1'; TEST=# create user U2 password 'u2'; TEST=# create user U3 password 'u3';
开启表的行级策略:
TEST=# alter table test enable row level security; ALTER TABLE
创建行级策略:
TEST=# \h create policy
Command: CREATE POLICY
Description: define a new row level security policy for a table
Syntax:
CREATE POLICY name ON table_name
[ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ]
[ TO { role_name | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ]
[ USING ( using_expression ) ]
[ WITH CHECK ( check_expression ) ]
--name -- 策略名称
--table_name -- 适用于该策略的表
--FOR -- 该策略适用的DML命令,ALL表示所有
--TO -- 该策略适用的角色
--USING -- 应用在表上的CHECK表达式,返回true的行可见,false不可见
--WITH CHECK -- 应用在该表的INSERT或UPDATE的SQL表达式,true的可以操作,false操作失败
创建查询的行级策略:
TEST=# create policy plcy1 on test for select using (user_name = current_user); CREATE POLICY TEST=# grant all on table test to u1, u2, u3; GRANT TEST=# \c TEST U1 Password for user U1: You are now connected to database "TEST" as user "U1". TEST=> select * from test; ID | USER_NAME | CRT_TIME ----+-----------+---------------------------- 1 | U1 | 2020-02-04 01:18:32.744308 4 | U1 | 2020-02-04 01:18:46.369409 (2 rows)
只有查询的行级策略,是不能修改对应的记录:
TEST=> update test set crt_time = now() where id = 1;
UPDATE 0
TEST=> update test set crt_time = now() where id = 4;
UPDATE 0
只有查询的行级策略,也不能插入对应的数据:
TEST=> insert into test(user_name) values('U1');
ERROR: permission denied for sequence TEST_ID_SEQ
TEST=> insert into test(id, user_name) values(8,'U1');
ERROR: new row violates row-level security policy for table "TEST"
添加策略,将所有DML命令都进行判断:
TEST=# create policy plcy2 on test for all using (user_name = current_user);
CREATE POLICY
TEST=# \c TEST U1
Password for user U1:
You are now connected to database "TEST" as user "U1".
TEST=> update test set crt_time = now() where id = 4;
UPDATE 1
TEST=> insert into test(user_name) values('U1');
ERROR: permission denied for sequence TEST_ID_SEQ
TEST=> insert into test(id,user_name) values(8,'U1');
INSERT 0 1
TEST=> select * from test;
ID | USER_NAME | CRT_TIME
----+-----------+----------------------------
1 | U1 | 2020-02-04 01:18:32.744308
4 | U1 | 2020-02-04 01:32:21.707241
8 | U1 | 2020-02-04 01:33:03.484166
(3 rows)
实验with check的检查,针对insert不能有using部分,update和delete则允许:
TEST=# create policy plcy5 on test for insert using (user_name = current_user) with check (user_name = current_user and id != 100); ERROR: only WITH CHECK expression allowed for INSERT TEST=# create policy plcy3 on test for insert with check (user_name = current_user and id != 100); CREATE POLICY TEST=# \c TEST U1 Password for user U1: You are now connected to database "TEST" as user "U1". TEST=> select * from test; ID | USER_NAME | CRT_TIME ----+-----------+---------------------------- 1 | U1 | 2020-02-04 01:18:32.744308 4 | U1 | 2020-02-04 01:32:21.707241 8 | U1 | 2020-02-04 01:33:03.484166 (3 rows) TEST=> insert into test(id, user_name) values(22, 'U1'); INSERT 0 1 还是能插入id为100的数据,因为前面有all的策略,导致所有只要是user_name = current_user 都可以插入,多个策略之间使用的是OR进行处理的: TEST=> insert into test(id, user_name) values(100, 'U1'); INSERT 0 1 TEST=> select * from test; ID | USER_NAME | CRT_TIME -----+-----------+---------------------------- 1 | U1 | 2020-02-04 01:18:32.744308 4 | U1 | 2020-02-04 01:32:21.707241 8 | U1 | 2020-02-04 01:33:03.484166 22 | U1 | 2020-02-04 01:40:46.900007 100 | U1 | 2020-02-04 01:40:54.127757 (5 rows) TEST=> delete from test where id > 10; DELETE 2 删除all的权限plcy2,plcy3就生效了: TEST=> \c TEST SYSTEM Password for user SYSTEM: You are now connected to database "TEST" as user "SYSTEM". TEST=# drop policy plcy2 on test; DROP POLICY TEST=# \c TEST U1 Password for user U1: You are now connected to database "TEST" as user "U1". TEST=> insert into test(id, user_name) values(22, 'U1'); INSERT 0 1 TEST=> insert into test(id, user_name) values(100, 'U1'); ERROR: new row violates row-level security policy for table "TEST" TEST=>
实验update策略:
TEST=# create policy plcy4 on test for update using (user_name = current_user) with check (user_name = current_user and id = 1); CREATE POLICY TEST=# \c TEST SYSTEM You are now connected to database "TEST" as user "SYSTEM". TEST=# \c TEST U1 Password for user U1: You are now connected to database "TEST" as user "U1". TEST=> select * from test; ID | USER_NAME | CRT_TIME ----+-----------+---------------------------- 1 | U1 | 2020-02-04 01:18:32.744308 4 | U1 | 2020-02-04 01:32:21.707241 8 | U1 | 2020-02-04 01:33:03.484166 22 | U1 | 2020-02-04 01:44:40.663172 (4 rows) TEST=> update test set crt_time = now() where id = 4; ERROR: new row violates row-level security policy for table "TEST" TEST=> update test set crt_time = now() where id = 1; UPDATE 1 TEST=> update test set crt_time = now() where id = 2; UPDATE 0 TEST=>
因此,常用的使用方法应该是:
create policy plcy2 on test for all using (user_name = current_user);
这样所有的用户只能看到自己的数据,而超级用户和表的所有者可以查看所有的数据:
TEST=# select * from test; ID | USER_NAME | CRT_TIME ----+-----------+---------------------------- 2 | U2 | 2020-02-04 01:18:35.119190 3 | U3 | 2020-02-04 01:18:37.341201 5 | U2 | 2020-02-04 01:18:49.056104 6 | U3 | 2020-02-04 01:18:51.435371 4 | U1 | 2020-02-04 01:32:21.707241 8 | U1 | 2020-02-04 01:33:03.484166 22 | U1 | 2020-02-04 01:44:40.663172 1 | U1 | 2020-02-04 01:48:59.705486 (8 rows) TEST=# \c TEST U1 Password for user U1: You are now connected to database "TEST" as user "U1". TEST=> select * from test; ID | USER_NAME | CRT_TIME ----+-----------+---------------------------- 4 | U1 | 2020-02-04 01:32:21.707241 8 | U1 | 2020-02-04 01:33:03.484166 22 | U1 | 2020-02-04 01:44:40.663172 1 | U1 | 2020-02-04 01:48:59.705486 (4 rows)
查看表的行级策略:
TEST=> \d test
Table "PUBLIC.TEST"
Column | Type | Modifiers
-----------+-----------------------------+---------------------------------------------------
ID | INTEGER | not null default NEXTVAL('TEST_ID_SEQ'::REGCLASS)
USER_NAME | CHARACTER VARYING(32 byte) |
CRT_TIME | TIMESTAMP WITHOUT TIME ZONE | default NOW()
Indexes:
"TEST_PKEY" PRIMARY KEY, BTREE (ID)
Policies:
POLICY "PLCY1" FOR SELECT
USING (((USER_NAME)::NAME = "CURRENT_USER"()))
POLICY "PLCY3" FOR INSERT
WITH CHECK ((((USER_NAME)::NAME = "CURRENT_USER"()) AND (ID <> 100)))
POLICY "PLCY4" FOR UPDATE
USING (((USER_NAME)::NAME = "CURRENT_USER"()))
WITH CHECK ((((USER_NAME)::NAME = "CURRENT_USER"()) AND (ID = 1)))
TEST=> select polname, polrelid, relname from pg_policy, pg_class c where polrelid = c.oid;
POLNAME | POLRELID | RELNAME
-------------------+----------+-----------------------
DENY_MODIFICATION | 14749 | PATHMAN_CONFIG
DENY_MODIFICATION | 14759 | PATHMAN_CONFIG_PARAMS
ALLOW_SELECT | 14749 | PATHMAN_CONFIG
ALLOW_SELECT | 14759 | PATHMAN_CONFIG_PARAMS
PLCY1 | 25146 | TEST
PLCY3 | 25146 | TEST
PLCY4 | 25146 | TEST
(7 rows)
严以律己、宽以待人

浙公网安备 33010602011771号