SlideShare ist ein Scribd-Unternehmen logo
1 von 26
Downloaden Sie, um offline zu lesen
Row Level Security
KaiGai Kohei <kaigai@kaigai.gr.jp>
tw: @kkaigai
How RLS should work (1/2)
                                SELECT * FROM drink;


                                       Security Policy
          ‘classified’                                                ‘unclassified’
                                       LabelU  LabelT


                   label               id          name               price
4 rows




               ‘unclassified’          10         ‘water’             100




                                                                                       2 rows
                ‘classified’           20          ‘coke’             120
               ‘unclassified’          30          ‘juice’            180
                ‘classified’           40         ‘sprite’            120
                  ‘secret’             50          ‘beer’             240
                  ‘secret’             60          ‘sake’             350
                                         table: drink

                         ROW LEVEL ACCESS CONTROL - 20130218 KaiGai                      2
How RLS should work (2/2)
                   SELECT * FROM drink NATURAL JOIN drink_order
                                      id    name      price   shop_id       quantum     data
                                      10   ‘water’    100       100            8      2013-02-16
     shop_id = 100                    30    ‘juice’   180       100           10      2013-02-18




                                                            Security Policy
id      name           price
                                                         shop_idU = shop_idT
10      ‘water’        100
20      ‘coke’         120                 id     shop_id        quantum              date

30      ‘juice’        180                 10         100               8          2013-02-16

40      ‘sprite’       120                 20         200               5          2013-02-17

50      ‘beer’         240                 10         200               6          2013-02-18

60      ‘sake’         350                 30         100             10           2013-02-18

        table: drink                                        table: drink_order

                       ROW LEVEL ACCESS CONTROL - 20130218 KaiGai                              3
WHERE is simple solution?
postgres=> CREATE VIEW soft_drink AS
     SELECT * FROM drink WHERE price < 200;
CREATE VIEW
postgres=> GRANT SELECT ON soft_drink TO public;
GRANT
postgres=> SET SESSION AUTHORIZATION bob;
SET
postgres=> SELECT * FROM soft_drink;
 id | name | price
----+--------+-------
 10 | water |    100
 20 | coke   |   120
 30 | juice |    180
 40 | sprite |   120
(4 rows)

postgres=> SELECT * FROM drink;
ERROR: permission denied for relation drink

             ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   4
Nightmare of Leaky View (1/3)
postgres=> SELECT * FROM soft_drink WHERE f_leak(name);
NOTICE: f_leak => water
NOTICE: f_leak => coke
NOTICE: f_leak => juice
NOTICE: f_leak => sprite
NOTICE: f_leak => beer
NOTICE: f_leak => sake
 id | name | price
----+--------+-------
 10 | water |    100
 20 | coke   |   120
 30 | juice |    180
 40 | sprite |   120
(4 rows)




             ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   5
Nightmare of Leaky View (2/3)
postgres=> CREATE OR REPLACE FUNCTION f_leak (text)
  RETURNS bool COST 0.000001 AS
  $$
  BEGIN
  RAISE NOTICE 'f_leak => %', $1;
  RETURN true;
  END
  $$ LANGUAGE plpgsql;
CREATE FUNCTION

postgres=> EXPLAIN(costs off)
  SELECT * FROM soft_drink WHERE f_leak(name);
                 QUERY PLAN
--------------------------------------------
 Seq Scan on drink
   Filter: (f_leak(name) AND (price < 200))
(2 rows)
                  f_leak() のコストは ‘<‘ 演算子より小さい

             ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   6
Nightmare of Leaky View (3/3)
postgres=> CREATE VIEW v_both AS
   SELECT * FROM t_left JOIN t_right ON a = x
   WHERE b like '%hoge%';
CREATE VIEW

postgres=> EXPLAIN (COSTS OFF)
   SELECT * FROM v_both WHERE f_leak(y);
                 QUERY PLAN
---------------------------------------------
 Hash Join
   Hash Cond: (t_left.x = t_right.a)
   -> Seq Scan on t_left
         Filter: f_leak(y)         f_leak()の実行は、
   -> Hash                         t_left だけに依存
         -> Seq Scan on t_right
               Filter: (b ~~ '%hoge%'::text)
(7 rows)



             ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   7
Problem to be tackled
SELECT * FROM v_both WHERE f_leak(y);
          
SELECT * FROM (
   SELECT * FROM t_left JOIN t_right ON a = x
       WHERE b like '%hoge%’
) AS v_both WHERE f_leak(y)


   問題の本質は、クエリ最適化が条件句を
    評価する順序を入れ替えてしまう事。
   少なくともセキュリティ目的のビューなら、
    サブクエリの境界を跨いで条件句を移動させては
    ならない。

              ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   8
Security Barrier (1/3)




      ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   9
Security Barrier (2/3)
postgres=> CREATE OR REPLACE VIEW soft_drink
             WITH (security_barrier)
             AS SELECT * FROM drink WHERE price < 200;
CREATE VIEW
postgres=> SET SESSION AUTHORIZATION bob;
SET
postgres=> SELECT * FROM soft_drink WHERE f_leak(name);
NOTICE: f_leak => water
NOTICE: f_leak => coke
NOTICE: f_leak => juice
NOTICE: f_leak => sprite
 id | name | price
----+--------+-------
 10 | water |    100
 20 | coke   |   120
 30 | juice |    180
 40 | sprite |   120
(4 rows)

             ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   10
Security Barrier (3/3)
postgres=> EXPLAIN (costs off)
           SELECT * FROM soft_drink WHERE f_leak(name);
            QUERY PLAN
-----------------------------------
 Subquery Scan on soft_drink
   Filter: f_leak(soft_drink.name)
   -> Seq Scan on drink
         Filter: (price < 200)
(4 rows)


   CREATE VIEW ... WITH (security_barrier) AS ...
   security_barrier属性を持つVIEWの内側へは、
    条件句を push-down させない。
       利用者が意図した通りの順序で条件句が評価される
       代償として、最適な実行性能は得られなくなる
              ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   11
Security-performance trade off
postgres=> CREATE VIEW my_team WITH (security_barrier)
    AS SELECT * FROM employee WHERE boss = current_user;
CREATE VIEW
postgres=> EXPLAIN (costs off)
           SELECT * FROM my_team WHERE id = 100;
                QUERY PLAN
-------------------------------------------
 Subquery Scan on my_team
   Filter: (my_team.id = 100)
   -> Seq Scan on employee
         Filter: (boss = "current_user"())
(4 rows)


   id = 100 を使ってインデックススキャンができるはず
   だが、security_barrier属性のために、先にemployeeを
    全件スキャン  その後で id = 100 を評価

              ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   12
Leakproof Function (1/3)




      ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   13
Leakproof Function (2/3)
   副作用の無い (= 間違いなく安全な) 関数なら、
    security_barrierビューの内側に押し込んでも大丈夫
      それを示すのが、LEAKPROOF 属性

postgres=# CREATE FUNCTION nabeatsu(integer)
            RETURNS bool LEAKPROOF AS
$$
BEGIN
   IF ($1 % 3 = 0) THEN RETURN true; END IF;
   WHILE $1 > 0 LOOP
     IF ($1 % 10 = 3) THEN RETURN true; END IF;
     $1 = $1 / 10;
   END LOOP;
RETURN false;
END
$$ LANGUAGE plpgsql;
CREATE FUNCTION

              ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   14
Leakproof Function (3/3)
postgres=> EXPLAIN (costs off)
           SELECT * FROM my_team WHERE nabeatsu(id);
                       QUERY PLAN
--------------------------------------------------------
 Seq Scan on employee
   Filter: ((boss = "current_user"()) AND nabeatsu(id))
(2 rows)

   デフォルトLEAKPROOFなビルトイン関数もある
       integer対integer の 等価演算子など
postgres=> EXPLAIN (costs off)
           SELECT * FROM my_team WHERE id = 300;
                 QUERY PLAN
--------------------------------------------
 Index Scan using employee_pkey on employee
   Index Cond: (id = 300)
   Filter: (boss = "current_user"())
(3 rows)
               ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   15
In case of Oracle
----------------------------------------------------
| Id | Operation            | Name | Rows | Bytes |
----------------------------------------------------
|   0 | SELECT STATEMENT    |      |     3 |    81 |
|* 1 | VIEW                 | V    |     3 |    81 |
|* 2 |    HASH JOIN         |      |     3 |   120 |
|* 3 |     TABLE ACCESS FULL| B    |     3 |    60 |
|   4 |    TABLE ACCESS FULL| A    |     4 |    80 |
----------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("F_LEAK"("X")=1) <== This is correct
   2 - access("A"."ID"="B"."ID")
   3 - filter("B"."Y"<>'bbb')




             ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   16
Toward v9.3, Beyond v9.3
   Feature list in v9.2
       VIEWのsecurity_barrier属性
       FUNCTIONのleakproof属性
   Feature list in v9.3(?)
       ALTER TABLE ... SET ROW SECURITY (...)
   Feature list in v9.4(???)
       Writer side checks
       Security label column
       Label based mandatory row-level access control




                ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   17
Syntax of Row-level Security (1/2)
ALTER <table_name>
    SET ROW SECURITY FOR <cmd>
    TO (<expression>);
<cmd> := ALL | SELECT | INSERT | UPDATE | DELETE

   <cmd> で指定したDML構文の実行時に、<expression>で
    指定した条件句(セキュリティポリシー)が付加される。
   クエリの条件句よりも、セキュリティポリシーが先に評価される。
postgres=> ALTER TABLE my_table
           SET ROW SECURITY FOR ALL TO (a % 2 = 0);
ALTER TABLE
postgres=> ALTER TABLE my_table
           SET ROW SECURITY FOR ALL TO
               (a = ANY(SELECT x FROM sub_tbl));
ALTER TABLE

              ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   18
Syntax of Row-level Security (2/2)
    ALTER t SET ROW SECURITY FOR ALL
            TO (owner = current_user);

    SELECT * FROM t WHERE f_leak(x);
                                   security_barrier
                                     付きサブクエリ
    SELECT * FROM (
        SELECT * FROM t WHERE owner = current_user
    ) t WHERE f_leak(x)

   テーブルへの参照  条件句付きテーブルスキャンを
    含むサブクエリ (with security_barrier) に置き換える。
   superuser の場合には適用されない。
        ビルトインRLSの場合。extensionが勝手に付けるのは自由。
                ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   19
How does RLS work? (1/2)
postgres=> ALTER TABLE t
        SET ROW SECURITY FOR ALL TO (owner = current_user);
ALTER TABLE

postgres=> EXPLAIN (costs off)
           SELECT * FROM t WHERE f_leak(b) AND a > 0;
                   QUERY PLAN
------------------------------------------------
 Subquery Scan on t
   Filter: f_leak(t.b)
   -> Index Scan using my_table_pkey on t t_1
         Index Cond: (owner = "current_user"())
         Filter: (a > 0)
(5 rows)




             ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   20
How does RLS work? (2/2)
postgres=> EXPLAIN (costs off)
           UPDATE t SET b = b WHERE f_leak(b);
                      QUERY PLAN
------------------------------------------------------
 Update on t
   -> Subquery Scan on t_1
         Filter: f_leak(t_1.b)
         -> Index Scan using my_table_pkey on t t_2
               Index Cond: (owner = "current_user"())

postgres=> EXPLAIN(costs off)
           DELETE FROM t WHERE f_leak(b);
                      QUERY PLAN
------------------------------------------------------
 Delete on t
   -> Subquery Scan on t_1
         Filter: f_leak(t_1.b)
         -> Index Scan using my_table_pkey on t t_2
               Index Cond: (owner = "current_user"())
              ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   21
Table Update and RLS (1/2)

          WHERE句の評価

                                                 ctid +      x   y       z


TargetListの計算


                                ctid      x          y               z
                               (0, 1)
    x’    y’   z’
                               (0, 2)
    +                          (0, 3)
                               (0, 4)
   ctid
                               (0, 5)



 ModifyTable                                  TableScan


                ROW LEVEL ACCESS CONTROL - 20130218 KaiGai                   22
Table Update and RLS (2/2)




                      z
                                                  WHERE句の評価
WHERE句の評価
                                                  (セキュリティポリシー)




                      y
                      x
                                                    ctid +      x   y       z

                      ctid +
TargetListの計算


                                   ctid      x          y               z
                                  (0, 1)
   x’    y’   z’
                                  (0, 2)
   +                              (0, 3)
                                  (0, 4)
  ctid
                                  (0, 5)



 ModifyTable                                     TableScan
                                            SubQueryScan

                   ROW LEVEL ACCESS CONTROL - 20130218 KaiGai                   23
Future development (1/2)
   SQLコマンド毎に異なるセキュリティポリシーの設定
   INSERT/UPDATEの直前にもチェックを入れる
       TargetListを計算した結果、それはPolicy Violationな値かもしれない!!




ここにチェックを
入れたい




               ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   24
Future development (2/2)
   Labal-based Row-level Security
       要は、SE-PostgreSQLの行レベルアクセス制御対応
   実現に向けたプロセス
       Row-level Security基本機能
       INSERT/UPDATE直前のチェック機能
       Security Label用の列を自動的に追加する機能
       要素の動的追加が可能な Enum 型
        これらを全部活用して contrib/sepgsql の機能拡張




              ROW LEVEL ACCESS CONTROL - 20130218 KaiGai   25
Any Questions?

Weitere ähnliche Inhalte

Andere mochten auch

Andere mochten auch (15)

Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)
Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)
Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)
 
Technology Updates of PG-Strom at Aug-2014 (PGUnconf@Tokyo)
Technology Updates of PG-Strom at Aug-2014 (PGUnconf@Tokyo)Technology Updates of PG-Strom at Aug-2014 (PGUnconf@Tokyo)
Technology Updates of PG-Strom at Aug-2014 (PGUnconf@Tokyo)
 
GPGPU Accelerates PostgreSQL ~Unlock the power of multi-thousand cores~
GPGPU Accelerates PostgreSQL ~Unlock the power of multi-thousand cores~GPGPU Accelerates PostgreSQL ~Unlock the power of multi-thousand cores~
GPGPU Accelerates PostgreSQL ~Unlock the power of multi-thousand cores~
 
PG-Strom
PG-StromPG-Strom
PG-Strom
 
SQL+GPU+SSD=∞ (English)
SQL+GPU+SSD=∞ (English)SQL+GPU+SSD=∞ (English)
SQL+GPU+SSD=∞ (English)
 
SQL+GPU+SSD=∞ (Japanese)
SQL+GPU+SSD=∞ (Japanese)SQL+GPU+SSD=∞ (Japanese)
SQL+GPU+SSD=∞ (Japanese)
 
20170127 JAWS HPC-UG#8
20170127 JAWS HPC-UG#820170127 JAWS HPC-UG#8
20170127 JAWS HPC-UG#8
 
pgconfasia2016 plcuda en
pgconfasia2016 plcuda enpgconfasia2016 plcuda en
pgconfasia2016 plcuda en
 
An Intelligent Storage?
An Intelligent Storage?An Intelligent Storage?
An Intelligent Storage?
 
20160407_GTC2016_PgSQL_In_Place
20160407_GTC2016_PgSQL_In_Place20160407_GTC2016_PgSQL_In_Place
20160407_GTC2016_PgSQL_In_Place
 
pgconfasia2016 lt ssd2gpu
pgconfasia2016 lt ssd2gpupgconfasia2016 lt ssd2gpu
pgconfasia2016 lt ssd2gpu
 
GPGPU Accelerates PostgreSQL (English)
GPGPU Accelerates PostgreSQL (English)GPGPU Accelerates PostgreSQL (English)
GPGPU Accelerates PostgreSQL (English)
 
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database AnalyticsPL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
 
PG-Strom - GPGPU meets PostgreSQL, PGcon2015
PG-Strom - GPGPU meets PostgreSQL, PGcon2015PG-Strom - GPGPU meets PostgreSQL, PGcon2015
PG-Strom - GPGPU meets PostgreSQL, PGcon2015
 
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database AnalyticsPL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
 

Ähnlich wie Row-level Security

Wait Events 10g
Wait Events 10gWait Events 10g
Wait Events 10g
sagai
 
Dbms lab 01 termwork1
Dbms lab 01 termwork1Dbms lab 01 termwork1
Dbms lab 01 termwork1
Jafar Nesargi
 
Database Development Replication Security Maintenance Report
Database Development Replication Security Maintenance ReportDatabase Development Replication Security Maintenance Report
Database Development Replication Security Maintenance Report
nyin27
 
metadatacoreProperties.xmlModel2017-10-12T151537Zgrv334grv3.docx
metadatacoreProperties.xmlModel2017-10-12T151537Zgrv334grv3.docxmetadatacoreProperties.xmlModel2017-10-12T151537Zgrv334grv3.docx
metadatacoreProperties.xmlModel2017-10-12T151537Zgrv334grv3.docx
ARIV4
 

Ähnlich wie Row-level Security (20)

OpenWorld Sep14 12c for_developers
OpenWorld Sep14 12c for_developersOpenWorld Sep14 12c for_developers
OpenWorld Sep14 12c for_developers
 
OpenWorld 2018 - Common Application Developer Disasters
OpenWorld 2018 - Common Application Developer DisastersOpenWorld 2018 - Common Application Developer Disasters
OpenWorld 2018 - Common Application Developer Disasters
 
New Tuning Features in Oracle 11g - How to make your database as boring as po...
New Tuning Features in Oracle 11g - How to make your database as boring as po...New Tuning Features in Oracle 11g - How to make your database as boring as po...
New Tuning Features in Oracle 11g - How to make your database as boring as po...
 
gumiStudy#2 実践 memcached
gumiStudy#2 実践 memcachedgumiStudy#2 実践 memcached
gumiStudy#2 実践 memcached
 
実践 memcached
実践 memcached実践 memcached
実践 memcached
 
Wait Events 10g
Wait Events 10gWait Events 10g
Wait Events 10g
 
Ipsec
IpsecIpsec
Ipsec
 
제 6회 엑셈 수요 세미나 자료 연구컨텐츠팀
제 6회 엑셈 수요 세미나 자료 연구컨텐츠팀제 6회 엑셈 수요 세미나 자료 연구컨텐츠팀
제 6회 엑셈 수요 세미나 자료 연구컨텐츠팀
 
Sql Injection Myths and Fallacies
Sql Injection Myths and FallaciesSql Injection Myths and Fallacies
Sql Injection Myths and Fallacies
 
Dbms lab 01 termwork1
Dbms lab 01 termwork1Dbms lab 01 termwork1
Dbms lab 01 termwork1
 
Php Security - OWASP
Php  Security - OWASPPhp  Security - OWASP
Php Security - OWASP
 
MySQL 8.0: not only good, it’s GREAT! - PHP UK 2019
MySQL 8.0: not only good, it’s GREAT! - PHP UK 2019MySQL 8.0: not only good, it’s GREAT! - PHP UK 2019
MySQL 8.0: not only good, it’s GREAT! - PHP UK 2019
 
Database Development Replication Security Maintenance Report
Database Development Replication Security Maintenance ReportDatabase Development Replication Security Maintenance Report
Database Development Replication Security Maintenance Report
 
Fase III De Mipe
Fase III De MipeFase III De Mipe
Fase III De Mipe
 
metadatacoreProperties.xmlModel2017-10-12T151537Zgrv334grv3.docx
metadatacoreProperties.xmlModel2017-10-12T151537Zgrv334grv3.docxmetadatacoreProperties.xmlModel2017-10-12T151537Zgrv334grv3.docx
metadatacoreProperties.xmlModel2017-10-12T151537Zgrv334grv3.docx
 
미움 받을 용기 : 저 팀은 뭘 안다고 추천한다고 들쑤시고 다니는건가
미움 받을 용기 : 저 팀은 뭘 안다고 추천한다고 들쑤시고 다니는건가미움 받을 용기 : 저 팀은 뭘 안다고 추천한다고 들쑤시고 다니는건가
미움 받을 용기 : 저 팀은 뭘 안다고 추천한다고 들쑤시고 다니는건가
 
Indexes From the Concept to Internals
Indexes From the Concept to InternalsIndexes From the Concept to Internals
Indexes From the Concept to Internals
 
Oracle Web Adi For upload item master
Oracle Web Adi For upload item masterOracle Web Adi For upload item master
Oracle Web Adi For upload item master
 
Connor McDonald 11g for developers
Connor McDonald 11g for developersConnor McDonald 11g for developers
Connor McDonald 11g for developers
 
12c Mini Lesson - Inline PLSQL from SQL
12c Mini Lesson - Inline PLSQL from SQL12c Mini Lesson - Inline PLSQL from SQL
12c Mini Lesson - Inline PLSQL from SQL
 

Mehr von Kohei KaiGai

Mehr von Kohei KaiGai (20)

20221116_DBTS_PGStrom_History
20221116_DBTS_PGStrom_History20221116_DBTS_PGStrom_History
20221116_DBTS_PGStrom_History
 
20221111_JPUG_CustomScan_API
20221111_JPUG_CustomScan_API20221111_JPUG_CustomScan_API
20221111_JPUG_CustomScan_API
 
20211112_jpugcon_gpu_and_arrow
20211112_jpugcon_gpu_and_arrow20211112_jpugcon_gpu_and_arrow
20211112_jpugcon_gpu_and_arrow
 
20210928_pgunconf_hll_count
20210928_pgunconf_hll_count20210928_pgunconf_hll_count
20210928_pgunconf_hll_count
 
20210731_OSC_Kyoto_PGStrom3.0
20210731_OSC_Kyoto_PGStrom3.020210731_OSC_Kyoto_PGStrom3.0
20210731_OSC_Kyoto_PGStrom3.0
 
20210511_PGStrom_GpuCache
20210511_PGStrom_GpuCache20210511_PGStrom_GpuCache
20210511_PGStrom_GpuCache
 
20210301_PGconf_Online_GPU_PostGIS_GiST_Index
20210301_PGconf_Online_GPU_PostGIS_GiST_Index20210301_PGconf_Online_GPU_PostGIS_GiST_Index
20210301_PGconf_Online_GPU_PostGIS_GiST_Index
 
20201128_OSC_Fukuoka_Online_GPUPostGIS
20201128_OSC_Fukuoka_Online_GPUPostGIS20201128_OSC_Fukuoka_Online_GPUPostGIS
20201128_OSC_Fukuoka_Online_GPUPostGIS
 
20201113_PGconf_Japan_GPU_PostGIS
20201113_PGconf_Japan_GPU_PostGIS20201113_PGconf_Japan_GPU_PostGIS
20201113_PGconf_Japan_GPU_PostGIS
 
20201006_PGconf_Online_Large_Data_Processing
20201006_PGconf_Online_Large_Data_Processing20201006_PGconf_Online_Large_Data_Processing
20201006_PGconf_Online_Large_Data_Processing
 
20200828_OSCKyoto_Online
20200828_OSCKyoto_Online20200828_OSCKyoto_Online
20200828_OSCKyoto_Online
 
20200806_PGStrom_PostGIS_GstoreFdw
20200806_PGStrom_PostGIS_GstoreFdw20200806_PGStrom_PostGIS_GstoreFdw
20200806_PGStrom_PostGIS_GstoreFdw
 
20200424_Writable_Arrow_Fdw
20200424_Writable_Arrow_Fdw20200424_Writable_Arrow_Fdw
20200424_Writable_Arrow_Fdw
 
20191211_Apache_Arrow_Meetup_Tokyo
20191211_Apache_Arrow_Meetup_Tokyo20191211_Apache_Arrow_Meetup_Tokyo
20191211_Apache_Arrow_Meetup_Tokyo
 
20191115-PGconf.Japan
20191115-PGconf.Japan20191115-PGconf.Japan
20191115-PGconf.Japan
 
20190926_Try_RHEL8_NVMEoF_Beta
20190926_Try_RHEL8_NVMEoF_Beta20190926_Try_RHEL8_NVMEoF_Beta
20190926_Try_RHEL8_NVMEoF_Beta
 
20190925_DBTS_PGStrom
20190925_DBTS_PGStrom20190925_DBTS_PGStrom
20190925_DBTS_PGStrom
 
20190909_PGconf.ASIA_KaiGai
20190909_PGconf.ASIA_KaiGai20190909_PGconf.ASIA_KaiGai
20190909_PGconf.ASIA_KaiGai
 
20190516_DLC10_PGStrom
20190516_DLC10_PGStrom20190516_DLC10_PGStrom
20190516_DLC10_PGStrom
 
20190418_PGStrom_on_ArrowFdw
20190418_PGStrom_on_ArrowFdw20190418_PGStrom_on_ArrowFdw
20190418_PGStrom_on_ArrowFdw
 

Row-level Security

  • 1. Row Level Security KaiGai Kohei <kaigai@kaigai.gr.jp> tw: @kkaigai
  • 2. How RLS should work (1/2) SELECT * FROM drink; Security Policy ‘classified’ ‘unclassified’ LabelU  LabelT label id name price 4 rows ‘unclassified’ 10 ‘water’ 100 2 rows ‘classified’ 20 ‘coke’ 120 ‘unclassified’ 30 ‘juice’ 180 ‘classified’ 40 ‘sprite’ 120 ‘secret’ 50 ‘beer’ 240 ‘secret’ 60 ‘sake’ 350 table: drink ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 2
  • 3. How RLS should work (2/2) SELECT * FROM drink NATURAL JOIN drink_order id name price shop_id quantum data 10 ‘water’ 100 100 8 2013-02-16 shop_id = 100 30 ‘juice’ 180 100 10 2013-02-18 Security Policy id name price shop_idU = shop_idT 10 ‘water’ 100 20 ‘coke’ 120 id shop_id quantum date 30 ‘juice’ 180 10 100 8 2013-02-16 40 ‘sprite’ 120 20 200 5 2013-02-17 50 ‘beer’ 240 10 200 6 2013-02-18 60 ‘sake’ 350 30 100 10 2013-02-18 table: drink table: drink_order ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 3
  • 4. WHERE is simple solution? postgres=> CREATE VIEW soft_drink AS SELECT * FROM drink WHERE price < 200; CREATE VIEW postgres=> GRANT SELECT ON soft_drink TO public; GRANT postgres=> SET SESSION AUTHORIZATION bob; SET postgres=> SELECT * FROM soft_drink; id | name | price ----+--------+------- 10 | water | 100 20 | coke | 120 30 | juice | 180 40 | sprite | 120 (4 rows) postgres=> SELECT * FROM drink; ERROR: permission denied for relation drink ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 4
  • 5. Nightmare of Leaky View (1/3) postgres=> SELECT * FROM soft_drink WHERE f_leak(name); NOTICE: f_leak => water NOTICE: f_leak => coke NOTICE: f_leak => juice NOTICE: f_leak => sprite NOTICE: f_leak => beer NOTICE: f_leak => sake id | name | price ----+--------+------- 10 | water | 100 20 | coke | 120 30 | juice | 180 40 | sprite | 120 (4 rows) ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 5
  • 6. Nightmare of Leaky View (2/3) postgres=> CREATE OR REPLACE FUNCTION f_leak (text) RETURNS bool COST 0.000001 AS $$ BEGIN RAISE NOTICE 'f_leak => %', $1; RETURN true; END $$ LANGUAGE plpgsql; CREATE FUNCTION postgres=> EXPLAIN(costs off) SELECT * FROM soft_drink WHERE f_leak(name); QUERY PLAN -------------------------------------------- Seq Scan on drink Filter: (f_leak(name) AND (price < 200)) (2 rows) f_leak() のコストは ‘<‘ 演算子より小さい ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 6
  • 7. Nightmare of Leaky View (3/3) postgres=> CREATE VIEW v_both AS SELECT * FROM t_left JOIN t_right ON a = x WHERE b like '%hoge%'; CREATE VIEW postgres=> EXPLAIN (COSTS OFF) SELECT * FROM v_both WHERE f_leak(y); QUERY PLAN --------------------------------------------- Hash Join Hash Cond: (t_left.x = t_right.a) -> Seq Scan on t_left Filter: f_leak(y) f_leak()の実行は、 -> Hash t_left だけに依存 -> Seq Scan on t_right Filter: (b ~~ '%hoge%'::text) (7 rows) ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 7
  • 8. Problem to be tackled SELECT * FROM v_both WHERE f_leak(y);  SELECT * FROM ( SELECT * FROM t_left JOIN t_right ON a = x WHERE b like '%hoge%’ ) AS v_both WHERE f_leak(y)  問題の本質は、クエリ最適化が条件句を 評価する順序を入れ替えてしまう事。  少なくともセキュリティ目的のビューなら、 サブクエリの境界を跨いで条件句を移動させては ならない。 ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 8
  • 9. Security Barrier (1/3) ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 9
  • 10. Security Barrier (2/3) postgres=> CREATE OR REPLACE VIEW soft_drink WITH (security_barrier) AS SELECT * FROM drink WHERE price < 200; CREATE VIEW postgres=> SET SESSION AUTHORIZATION bob; SET postgres=> SELECT * FROM soft_drink WHERE f_leak(name); NOTICE: f_leak => water NOTICE: f_leak => coke NOTICE: f_leak => juice NOTICE: f_leak => sprite id | name | price ----+--------+------- 10 | water | 100 20 | coke | 120 30 | juice | 180 40 | sprite | 120 (4 rows) ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 10
  • 11. Security Barrier (3/3) postgres=> EXPLAIN (costs off) SELECT * FROM soft_drink WHERE f_leak(name); QUERY PLAN ----------------------------------- Subquery Scan on soft_drink Filter: f_leak(soft_drink.name) -> Seq Scan on drink Filter: (price < 200) (4 rows)  CREATE VIEW ... WITH (security_barrier) AS ...  security_barrier属性を持つVIEWの内側へは、 条件句を push-down させない。  利用者が意図した通りの順序で条件句が評価される  代償として、最適な実行性能は得られなくなる ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 11
  • 12. Security-performance trade off postgres=> CREATE VIEW my_team WITH (security_barrier) AS SELECT * FROM employee WHERE boss = current_user; CREATE VIEW postgres=> EXPLAIN (costs off) SELECT * FROM my_team WHERE id = 100; QUERY PLAN ------------------------------------------- Subquery Scan on my_team Filter: (my_team.id = 100) -> Seq Scan on employee Filter: (boss = "current_user"()) (4 rows)  id = 100 を使ってインデックススキャンができるはず  だが、security_barrier属性のために、先にemployeeを 全件スキャン  その後で id = 100 を評価 ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 12
  • 13. Leakproof Function (1/3) ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 13
  • 14. Leakproof Function (2/3)  副作用の無い (= 間違いなく安全な) 関数なら、 security_barrierビューの内側に押し込んでも大丈夫  それを示すのが、LEAKPROOF 属性 postgres=# CREATE FUNCTION nabeatsu(integer) RETURNS bool LEAKPROOF AS $$ BEGIN IF ($1 % 3 = 0) THEN RETURN true; END IF; WHILE $1 > 0 LOOP IF ($1 % 10 = 3) THEN RETURN true; END IF; $1 = $1 / 10; END LOOP; RETURN false; END $$ LANGUAGE plpgsql; CREATE FUNCTION ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 14
  • 15. Leakproof Function (3/3) postgres=> EXPLAIN (costs off) SELECT * FROM my_team WHERE nabeatsu(id); QUERY PLAN -------------------------------------------------------- Seq Scan on employee Filter: ((boss = "current_user"()) AND nabeatsu(id)) (2 rows)  デフォルトLEAKPROOFなビルトイン関数もある  integer対integer の 等価演算子など postgres=> EXPLAIN (costs off) SELECT * FROM my_team WHERE id = 300; QUERY PLAN -------------------------------------------- Index Scan using employee_pkey on employee Index Cond: (id = 300) Filter: (boss = "current_user"()) (3 rows) ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 15
  • 16. In case of Oracle ---------------------------------------------------- | Id | Operation | Name | Rows | Bytes | ---------------------------------------------------- | 0 | SELECT STATEMENT | | 3 | 81 | |* 1 | VIEW | V | 3 | 81 | |* 2 | HASH JOIN | | 3 | 120 | |* 3 | TABLE ACCESS FULL| B | 3 | 60 | | 4 | TABLE ACCESS FULL| A | 4 | 80 | ---------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("F_LEAK"("X")=1) <== This is correct 2 - access("A"."ID"="B"."ID") 3 - filter("B"."Y"<>'bbb') ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 16
  • 17. Toward v9.3, Beyond v9.3  Feature list in v9.2  VIEWのsecurity_barrier属性  FUNCTIONのleakproof属性  Feature list in v9.3(?)  ALTER TABLE ... SET ROW SECURITY (...)  Feature list in v9.4(???)  Writer side checks  Security label column  Label based mandatory row-level access control ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 17
  • 18. Syntax of Row-level Security (1/2) ALTER <table_name> SET ROW SECURITY FOR <cmd> TO (<expression>); <cmd> := ALL | SELECT | INSERT | UPDATE | DELETE  <cmd> で指定したDML構文の実行時に、<expression>で 指定した条件句(セキュリティポリシー)が付加される。  クエリの条件句よりも、セキュリティポリシーが先に評価される。 postgres=> ALTER TABLE my_table SET ROW SECURITY FOR ALL TO (a % 2 = 0); ALTER TABLE postgres=> ALTER TABLE my_table SET ROW SECURITY FOR ALL TO (a = ANY(SELECT x FROM sub_tbl)); ALTER TABLE ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 18
  • 19. Syntax of Row-level Security (2/2) ALTER t SET ROW SECURITY FOR ALL TO (owner = current_user); SELECT * FROM t WHERE f_leak(x);  security_barrier 付きサブクエリ SELECT * FROM ( SELECT * FROM t WHERE owner = current_user ) t WHERE f_leak(x)  テーブルへの参照  条件句付きテーブルスキャンを 含むサブクエリ (with security_barrier) に置き換える。  superuser の場合には適用されない。  ビルトインRLSの場合。extensionが勝手に付けるのは自由。 ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 19
  • 20. How does RLS work? (1/2) postgres=> ALTER TABLE t SET ROW SECURITY FOR ALL TO (owner = current_user); ALTER TABLE postgres=> EXPLAIN (costs off) SELECT * FROM t WHERE f_leak(b) AND a > 0; QUERY PLAN ------------------------------------------------ Subquery Scan on t Filter: f_leak(t.b) -> Index Scan using my_table_pkey on t t_1 Index Cond: (owner = "current_user"()) Filter: (a > 0) (5 rows) ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 20
  • 21. How does RLS work? (2/2) postgres=> EXPLAIN (costs off) UPDATE t SET b = b WHERE f_leak(b); QUERY PLAN ------------------------------------------------------ Update on t -> Subquery Scan on t_1 Filter: f_leak(t_1.b) -> Index Scan using my_table_pkey on t t_2 Index Cond: (owner = "current_user"()) postgres=> EXPLAIN(costs off) DELETE FROM t WHERE f_leak(b); QUERY PLAN ------------------------------------------------------ Delete on t -> Subquery Scan on t_1 Filter: f_leak(t_1.b) -> Index Scan using my_table_pkey on t t_2 Index Cond: (owner = "current_user"()) ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 21
  • 22. Table Update and RLS (1/2) WHERE句の評価 ctid + x y z TargetListの計算 ctid x y z (0, 1) x’ y’ z’ (0, 2) + (0, 3) (0, 4) ctid (0, 5) ModifyTable TableScan ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 22
  • 23. Table Update and RLS (2/2) z WHERE句の評価 WHERE句の評価 (セキュリティポリシー) y x ctid + x y z ctid + TargetListの計算 ctid x y z (0, 1) x’ y’ z’ (0, 2) + (0, 3) (0, 4) ctid (0, 5) ModifyTable TableScan SubQueryScan ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 23
  • 24. Future development (1/2)  SQLコマンド毎に異なるセキュリティポリシーの設定  INSERT/UPDATEの直前にもチェックを入れる  TargetListを計算した結果、それはPolicy Violationな値かもしれない!! ここにチェックを 入れたい ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 24
  • 25. Future development (2/2)  Labal-based Row-level Security  要は、SE-PostgreSQLの行レベルアクセス制御対応  実現に向けたプロセス  Row-level Security基本機能  INSERT/UPDATE直前のチェック機能  Security Label用の列を自動的に追加する機能  要素の動的追加が可能な Enum 型   これらを全部活用して contrib/sepgsql の機能拡張 ROW LEVEL ACCESS CONTROL - 20130218 KaiGai 25