zoukankan      html  css  js  c++  java
  • postgresql-行级安全-RLS

    行级安全-RLS

    行级安全策略

    9.5版本新增的特性,该特性是在数据库授权体系下提供的更细粒度的控制。通俗的说就是不同用户可以看到表中不同的数据,这种控制是行级别的

    9.5以前的数据库安全技术是通过grant/revoke来实现的,这两个指令提供了对象级的安全限制,针对表还有列级别的安全限制。

    所有对数据的操作,暴扣数据查询和更新,都受策略的限制,如果没有配置安全策略,所有的查询和更新都会禁止,但是对全表进行操作的命令,truncate和refrences不受影响

    行级安全策略可以加在命令上,也可以加在角色上,也可以两者都加。命令可以是 ALL, SELECT, INSERT, UPDATE 和
    DELETE, 同一个策略也可以赋予多个角色。但是表的所有者,超级用户 (postgres) 以及加上了 BYPASSRLS
    属性的角色不受安全性的限制。如果应用想忽略行级安全性机制的限制,也可以将 row_security 设置为 off。

    CREATE POLICY ALTER POLICY DROP POLICY 命令分别用于策略的创建、修改和删除, ALTER TABLE 可以用于行级安全性的启用 / 禁用。

    每个策略都有一个名字,每个表可以定义多个策略,因为策略是针对表的,所以表内的多个策略名字必须唯一,但是不同的表可以有同名的策略,当表有多个策略时,多个策略之间是 OR 的关系。

    语法

    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 ) ]
    using:针对已经存在的记录的校验,可实施在select,update,delete,all上
    with check:针对将要新增的记录的校验,可实施在insert,update,all上
    update因为涉及旧的数据和新的记录,如果只写了using,但是没有提供with check的话,using同时会当成with check来进行检查
    
    如果针对同样的命令创建了多个策略, 所有策略中任意一个为TRUE都通过.
    
    例如ALL, SELECT各创建了一个策略for role r1, 执行select时任意一个为TRUE都通过.
    
    
    • 开启了安全策略后,普通用户能否正常访问数据?

    • 更新策略(更新是标记为删除后插入,也可以看出先查询后插入)需要注意什么?

    --创建三个用户
    postgres=# create role r1 login;
    CREATE ROLE
    postgres=# create role r2 login;
    CREATE ROLE
    postgres=# create role r3 login;
    CREATE ROLE
    
    --创建表
    postgres=# create table test(id int, r name);  
    CREATE TABLE
    postgres=#  insert into test values(1, 'r1');  
    INSERT 0 1
    postgres=# insert into test values(2, 'r2');  
    INSERT 0 1
    postgres=# insert into test values(3, 'r3');  
    INSERT 0 1
    postgres=#  grant all on table test to public;  
    GRANT
    
    --创建一个新增数据的策略,with check
    postgres=# create policy p on test for insert to r1 with check( r = current_user);
    CREATE POLICY
    postgres=# 
    
    --默认情况下状态是disable状态
    postgres=# d+ test
                             Table "public.test"
     Column |  Type   | Modifiers | Storage | Stats target | Description 
    --------+---------+-----------+---------+--------------+-------------
     id     | integer |           | plain   |              | 
     r      | name    |           | plain   |              | 
    Policies (row security disabled):
        POLICY "p" FOR INSERT
          TO r1
          WITH CHECK ((r = "current_user"()))
    
    --pg_policies可以查看已经创建的策略
    postgres=# select * from pg_policies;
     schemaname | tablename | policyname | roles |  cmd   | qual |       with_check       
    ------------+-----------+------------+-------+--------+------+------------------------
     public     | test      | p          | {r1}  | INSERT |      | (r = "current_user"())
    (1 row)
    
    postgres=# c postgres r1
    FATAL:  permission denied for database "postgres"
    DETAIL:  User does not have CONNECT privilege.
    Previous connection kept
    --赋予连接权限
    postgres=# grant connect on database postgres to r1;
    GRANT
    postgres=# grant connect on database postgres to r2;
    GRANT
    postgres=# grant connect on database postgres to r3;
    GRANT
    
    --在策略是disable状态的时候,策略视为无效状态
    postgres=# c postgres r1
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "r1".
    postgres=> 
    postgres=> insert into test values(4,'r1');
    INSERT 0 1
    postgres=> insert into test values(4,'r2');
    INSERT 0 1
    postgres=> 
    
    --使策略生效
    postgres=> c postgres sa
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "sa".
    postgres=# alter table test enable row level security;
    ALTER TABLE
    
    --再次插入数据就只能插入和r1角色同名的r值,r1用户插入了r2值会报错
    postgres=# c postgres r1
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "r1".
    postgres=> insert into test values(4,'r2');
    ERROR:  new row violates row-level security policy for table "test"
    postgres=> insert into test values(4,'r1');
    INSERT 0 1
    
    • 新增策略
    --新增一个策略,r1角色插入test表时,允许r字段的值为‘r1’和’r2‘
    postgres=> c postgres sa
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "sa".
    postgres=# create policy p1 on test for insert to r1 with check( r = 'r2');  
    CREATE POLICY
    postgres=# 
    postgres=# c postgres r1
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "r1".
    postgres=> insert into test values(4,'r2');  
    INSERT 0 1
    postgres=> insert into test values(4,'r1');  
    INSERT 0 1
    postgres=> insert into test values(4,'r3');  
    ERROR:  new row violates row-level security policy for table "test"
    
    postgres=> d+ test
                             Table "public.test"
     Column |  Type   | Modifiers | Storage | Stats target | Description 
    --------+---------+-----------+---------+--------------+-------------
     id     | integer |           | plain   |              | 
     r      | name    |           | plain   |              | 
    Policies:
        POLICY "p" FOR INSERT
          TO r1
          WITH CHECK ((r = "current_user"()))
        POLICY "p1" FOR INSERT
          TO r1
          WITH CHECK ((r = 'r2'::name))
    
    
    
    • 开启策略后,普通用户无法在访问数据
    postgres=> c postgres r2
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "r2".
    postgres=> select  * from test;
     id | r 
    ----+---
    (0 rows)
    
    postgres=> c postgres r1
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "r1".
    postgres=> select * from test;
     id | r 
    ----+---
    (0 rows)
    
    • 查询策略
    --r1只能查看到r='r1'的数据
    postgres=> c postgres sa
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "sa".
    postgres=# create policy p2 on test for select to r1 using ( r = current_user);  
    CREATE POLICY
    postgres=# 
    postgres=# c postgres r1
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "r1".
    postgres=> select * from test;
     id | r  
    ----+----
      1 | r1
      4 | r1
      4 | r1
      4 | r1
    (4 rows)
    
    
    --创建所有用户只能看到r= current_user,to public
    postgres=> c postgres sa
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "sa".
    postgres=# create policy p3 on test for select to public using ( r = current_user);  
    CREATE POLICY
    postgres=# c postgres r2
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "r2".
    postgres=> select * from test;
     id | r  
    ----+----
      2 | r2
      4 | r2
      4 | r2
    (3 rows)
    
    • 更新策略
    --创建更新策略
    postgres=# create policy p4 on test for update to r3 using(r=current_user);
    CREATE POLICY
    
    --删除开始的策略
    postgres=# drop policy p on test;
    DROP POLICY
    postgres=# drop policy p1 on test;
    DROP POLICY
    postgres=# drop policy p2 on test;
    DROP POLICY
    postgres=# drop policy p3 on test;
    DROP POLICY
    postgres=# d+ test
                             Table "public.test"
     Column |  Type   | Modifiers | Storage | Stats target | Description 
    --------+---------+-----------+---------+--------------+-------------
     id     | integer |           | plain   |              | 
     r      | name    |           | plain   |              | 
    Policies:
        POLICY "p4" FOR UPDATE
          TO r3
          USING ((r = "current_user"()))
    
    postgres=# c postgres r3
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "r3".
    --更新数据为0,是没有创建查询策略?
    postgres=> update test set id=4 where r = 'r3';
    UPDATE 0
    postgres=> select * from test;
     id | r 
    ----+---
    (0 rows)
    
    --创建了查询策略后,数据可以正常更新
    postgres=> c postgres sa
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "sa".
    postgres=# create policy p1 on test for select to r3 using ( r = current_user);  
    CREATE POLICY
    postgres=# c postgres r3
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "r3".
    postgres=> select * from test;
     id | r  
    ----+----
      3 | r3
    (1 row)
    --常见查询策略后,更新了数据
    postgres=> update test set id=4 where r = 'r3';
    UPDATE 1
    
    
    • 策略只针对非超级用户和非owner
    --超级用户可以看到所有数据
    postgres=> c postgres sa
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "sa".
    postgres=# select * from test;
     id | r  
    ----+----
      1 | r1
      2 | r2
      3 | r3
      4 | r1
      4 | r2
      4 | r1
      4 | r2
      4 | r1
    (8 rows)
    
    postgres=# alter role r1 superuser;
    ALTER ROLE
    postgres=# c postgres r1
    psql (9.6.4, server 9.5.3)
    You are now connected to database "postgres" as user "r1".
    postgres=# select * from test;
     id | r  
    ----+----
      1 | r1
      2 | r2
      3 | r3
      4 | r1
      4 | r2
      4 | r1
      4 | r2
      4 | r1
    (8 rows)
    
    • 普通用户对添加了行级安全策略的表pg_dump或者pg_restore时会报错
     pg_dump -U r1 -d postgres -p 5432 -t public.test
    pg_dump: [archiver (db)] query failed: ERROR:  query would be affected by row-level security policy for table "test"
    pg_dump: [archiver (db)] query was: COPY public.test (id, r) TO stdout;
    
    

    CREATE POLICY ALTER POLICY DROP POLICY 命令分别用于策略的创建、修改和删除, ALTER TABLE 可以用于行级安全性的启用 / 禁用。

    每个策略都有一个名字,每个表可以定义多个策略,因为策略是针对表的,所以表内的多个策略名字必须唯一,但是不同的表可以有同名的策略,当表有多个策略时,多个策略之间是 OR 的关系。

    RLS参考资料
    RLS参考资料

  • 相关阅读:
    css实现鼠标悬浮字体流光背景模糊效果
    原生JS实现省市区(县)三级联动选择
    多线程的对象锁和类锁
    session、cookie与“记住我的登录状态”的功能的实现
    Java NIO FileVisitor 高效删除文件
    mysql 服务启动失败
    Http 协议详解
    设计模式 之 策略模式
    简单探讨 javascript 闭包
    数据库SQL优化大总结之 百万级数据库优化方案
  • 原文地址:https://www.cnblogs.com/zhangfx01/p/14367567.html
Copyright © 2011-2022 走看看