sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLのsecurity_barrierビューはどのように機能しますか?

    security_barrierに追加されたサポートを見たことがあるかもしれません PostgreSQL9.2のビュー。 AXLEプロジェクトの進行中の行レベルのセキュリティ作業の一環として、自動更新サポートを追加することを目的としてそのコードを調査してきました。その仕組みを説明する機会があればと思いました。

    >

    ロバートは、なぜそれらが有用であり、何から保護するのかをすでに説明しました。 (9.2の新機能でも説明されていることがわかります)。次に、方法について説明します。 彼らは働き、 security_barrierがどのように機能するかについて話し合います ビューは自動的に更新可能なビューと相互作用します。

    通常のビュー

    通常の単純なビューは、サブクエリとしてマクロのように展開されます。サブクエリは通常、述語をプルアップして、含まれているクエリの品質に追加することで最適化されます。例を挙げれば、それはもっと理にかなっているかもしれません。与えられた表:

    CREATE TABLE t AS SELECT n, 'secret'||n AS secret FROM generate_series(1,20) n;

    と表示:

    CREATE VIEW t_odd AS SELECT n, secret FROM t WHERE n % 2 = 1;

    次のようなクエリ:

    SELECT * FROM t_odd WHERE n < 4

    は、クエリリライタ内で、次のようなクエリの解析ツリー表現にビュー拡張されます。

    SELECT * FROM (SELECT * FROM t WHERE n % 2 = 1) t_odd WHERE n < 4

    次に、オプティマイザは、サブクエリを削除して WHERE を追加することにより、シングルパスクエリにフラット化します。 外側のクエリに対する句の用語、生成:

    SELECT * FROM t t_odd WHERE (n % 2 = 1) AND (n < 4)

    中間クエリを直接表示することはできず、実際のSQLとして存在することはありませんが、 debug_print_parse =on を有効にすると、このプロセスを監視できます。 、 debug_print_rewritten =on およびdebug_print_plan=on postgresql.conf内 。解析ツリーと計画ツリーは非常に大きく、上記の例に基づいて簡単に生成できるため、ここでは再現しません。

    セキュリティのためにビューを使用する際の問題

    基になるテーブルへのアクセスを許可せずにビューへのアクセスを許可すると、偶数行が表示されなくなると考えるかもしれません。最初はそれが本当のように見えます:

    regress=> SELECT * FROM t_odd WHERE n < 4;
     n | secret  
    ---+---------
     1 | secret1
     3 | secret3
    (2 rows)

    ただし、計画を見ると、潜在的な問題が発生する可能性があります。

    regress=> EXPLAIN SELECT * FROM t_odd WHERE n < 4;
                        QUERY PLAN                     
    ---------------------------------------------------
     Seq Scan on t  (cost=0.00..31.53 rows=2 width=36)
       Filter: ((n < 4) AND ((n % 2) = 1))
    (2 rows)

    ビューのサブクエリは最適化されており、ビューの修飾子が外部のクエリに直接追加されています。

    SQLでは、 AND およびまたは 注文されていません。オプティマイザー/エグゼキューターは、迅速な回答が得られる可能性が高く、他のブランチの実行を回避できる可能性が高いと思われるブランチを自由に実行できます。したがって、プランナーが n <4と考える場合 n%2 =1よりもはるかに高速です 最初にそれを評価します。無害のようですよね?試してみてください:

    regress=> CREATE OR REPLACE FUNCTION f_leak(text) RETURNS boolean AS $$
    BEGIN
      RAISE NOTICE 'Secret is: %',$1;
      RETURN true;
    END;
    $$ COST 1 LANGUAGE plpgsql;
    
    regress=> SELECT * FROM t_odd WHERE f_leak(secret) AND n < 4;
    NOTICE:  Secret is: secret1
    NOTICE:  Secret is: secret2
    NOTICE:  Secret is: secret3
    NOTICE:  Secret is: secret4
    NOTICE:  Secret is: secret5
    NOTICE:  Secret is: secret6
    NOTICE:  Secret is: secret7
    NOTICE:  Secret is: secret8
    NOTICE:  Secret is: secret9
    NOTICE:  Secret is: secret10
    NOTICE:  Secret is: secret11
    NOTICE:  Secret is: secret12
    NOTICE:  Secret is: secret13
    NOTICE:  Secret is: secret14
    NOTICE:  Secret is: secret15
    NOTICE:  Secret is: secret16
    NOTICE:  Secret is: secret17
    NOTICE:  Secret is: secret18
    NOTICE:  Secret is: secret19
    NOTICE:  Secret is: secret20
     n | secret  
    ---+---------
     1 | secret1
     3 | secret3
    (2 rows)
    
    regress=> EXPLAIN SELECT * FROM t_odd WHERE f_leak(secret) AND n < 4;
                            QUERY PLAN                        
    ----------------------------------------------------------
     Seq Scan on t  (cost=0.00..34.60 rows=1 width=36)
       Filter: (f_leak(secret) AND (n < 4) AND ((n % 2) = 1))
    (2 rows)

    おっと!ご覧のとおり、ユーザー指定の述語関数は他のテストよりも実行コストが低いと考えられていたため、ビューの述語が除外する前にすべての行に合格しました。悪意のある関数が同じトリックを使用して行をコピーする可能性があります。

    security_barrier ビュー

    security_barrier ビューは、ユーザー指定の修飾子が実行される前に、ビューの修飾子を最初に実行するように強制することで、これを修正します。ビューを展開して外部クエリにビュー修飾子を追加する代わりに、ビューへの参照をサブクエリに置き換えます。このサブクエリにはsecurity_barrierがあります 範囲テーブルエントリに設定されたフラグ。これは、通常のサブクエリの場合のように、サブクエリをフラット化したり、外部クエリ条件をプッシュダウンしたりしないようにオプティマイザに指示します。

    したがって、セキュリティバリアビューを使用する場合:

    CREATE VIEW t_odd_sb WITH (security_barrier) AS SELECT n, secret FROM t WHERE n % 2 = 1;

    取得:

    regress=> SELECT * FROM t_odd_sb WHERE f_leak(secret) AND n < 4;
    NOTICE:  Secret is: secret1
    NOTICE:  Secret is: secret3
     n | secret  
    ---+---------
     1 | secret1
     3 | secret3
    (2 rows)
    
    regress=> EXPLAIN SELECT * FROM t_odd_sb WHERE f_leak(secret) AND n < 4;
                              QUERY PLAN                           
    ---------------------------------------------------------------
     Subquery Scan on t_odd_sb  (cost=0.00..31.55 rows=1 width=36)
       Filter: f_leak(t_odd_sb.secret)
       ->  Seq Scan on t  (cost=0.00..31.53 rows=2 width=36)
             Filter: ((n < 4) AND ((n % 2) = 1))
    (4 rows)

    クエリプランは何が起こっているかを教えてくれるはずですが、explain出力にはセキュリティバリア属性は表示されません。ネストされたサブクエリは、 tでスキャンを強制します ビュー修飾子を使用すると、ユーザー指定の関数がサブクエリの結果に対して実行されます。

    だが。ちょっと待って。ユーザー提供の述語n<4はなぜですか サブクエリ内にも?それは潜在的なセキュリティホールではありませんか? n <4の場合 押し下げられたのに、なぜ f_leak(secret)ではないのですか ?

    リークプルーフ 演算子と関数

    その説明は、 < 演算子はLEAKPROOFとマークされています 。この属性は、オペレーターまたは関数が情報を漏らさないことが信頼されていることを示しているため、 security_barrierを介して安全にプッシュダウンできます。 ビュー。明らかな理由により、 LEAKPROOFを設定することはできません 通常のユーザーとして:

    regress=> ALTER FUNCTION f_leak(text)  LEAKPROOF;
    ERROR:  only superuser can define a leakproof function

    スーパーユーザーはすでにやりたいことができるので、セキュリティバリアビューを乗り越えるために情報を漏らす機能を使ってトリックをする必要はありません。

    security_barrierを更新できないのはなぜですか ビュー

    PostgreSQL 9.3の単純なビューは自動的に更新可能ですが、 security_barrier ビューは「単純」とは見なされません。これは、ビューの更新は、ビューのサブクエリをフラット化して、更新をテーブルの単純な更新に変えることができることに依存しているためです。 security_barrierの要点 ビューは防止することです その平坦化。 更新 現在、サブクエリを直接操作することはできないため、PostgreSQLは security_barrierを更新する試みを拒否します。 ビュー:

    regress=> UPDATE t_odd SET secret = 'secret_haha'||n;
    UPDATE 10
    regress=> UPDATE t_odd_sb SET secret = 'secret_haha'||n;
    ERROR:  cannot update view "t_odd_sb"
    DETAIL:  Security-barrier views are not automatically updatable.
    HINT:  To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.
    

    AXLEプロジェクトの行レベルのセキュリティを向上させるための作業の一環として、この制限を解除することに関心があります。 Kohei KaiGaiは、行レベルのセキュリティと security_barrierのような機能で素晴らしい仕事をしました。 およびLEAKPROOF PostgreSQLに行レベルのセキュリティを追加することに向けた彼の仕事から主に生じました。次の課題は、セキュリティバリアの更新を安全に、将来にわたって維持できる方法で処理する方法です。

    サブクエリを実行する理由

    なぜこれにサブクエリを使用する必要があるのか​​疑問に思われるかもしれません。やった。短いバージョンでは、その必要はありませんが、サブクエリを使用しない場合は、代わりに ANDの新しい順序に依存するバリアントを作成する必要があります。 およびまたは オペレーターとオプティマイザーに、条件をそれらの間で移動できないことを教えます。ビューはすでにサブクエリとして展開されているため、プルアップ/プッシュダウンをブロックするフェンスとしてサブクエリにフラグを立てるだけで済みます。

    ただし、PostgreSQLにはすでに短絡した順序付き操作があります– CASE CASEの使用に関する問題 そのいいえ 操作はCASEの境界を越えて移動できます 、 LEAKPROOF もの。また、オプティマイザは、 CASE内の式に基づいてインデックスの使用を決定することもできません。 期間。したがって、 CASEを使用した場合 ハッカーについて尋ねたように、ユーザーが指定した修飾子を満たすためにインデックスを使用することはできませんでした。

    コード内

    security_barrier 0e4611c0234d89e288a53351f775c59522baed7cでサポートが追加されました 。 cd30728fb2ed7c367d545fc14ab850b5fa2a4850のリークプルーフサポートで強化されました 。クレジットはコミットノートに表示されます。関係者全員に感謝します。

    フロントページの機能画像は、FlikrのCraigA.Rodwayによるセキュリティバリアです

    これらの結果につながる研究は、助成金契約番号318633に基づいて欧州連合の第7フレームワークプログラム(FP7 / 2007-2013)から資金提供を受けています


    1. SQLiteOpenHelperを使用してAndroidでsqliteデータベースをアタッチする

    2. 意見を求める:すべてのテーブルに対して1つのシーケンス

    3. スプリングブートを取得してデータベーススキーマを自動的に作成できない

    4. エンティティで主キーのないビューを使用する