2016-01-03 7 views
10

Webアプリケーションをサポートするマルチテナントデータベースで新しい行レベルのセキュリティ機能を使用する最良の方法を理解しています。PostgreSQL 9.5 - 行レベルのセキュリティ/ ROLEのベストプラクティス

現在、アプリケーションでは、実行しようとしている操作によって、いくつかの異なる役割が利用できます。

アプリケーションが独自のROLEを使用して接続すると、アプリケーションはユーザーが指定した認証パラメータに基づいて行を除外するさまざまな機能にユーザーが提供する認証パラメータを渡します。このシステムは何千人ものユーザーと連携して動作するように設計されており、動作するようです。しかし、それは反抗的にclunky(そして遅い)です。

新しい行レベルのセキュリティ機能を使用する場合は、データベースにアクセスするために実際の各ユーザー(Webアプリケーションだけでなく)に新しいROLEを作成する必要があるようです。

これは間違いありませんか?もしそうなら、何千ものROLEをデータベースに作成することをお勧めしますか?私は下にあったように私はcurrent_setting('app_name.app_user')によって混乱している、今

CREATE USER application; 

CREATE TABLE t1 (id int primary key, f1 text, app_user text); 
INSERT INTO t1 VALUES(1,'a','bob'); 
INSERT INTO t1 VALUES(2,'b','alice'); 
ALTER TABLE t1 ENABLE ROW LEVEL SECURITY; 
CREATE POLICY P ON t1 USING (app_user = current_setting('app_name.app_user')); 
GRANT SELECT ON t1 TO application; 

SET SESSION AUTHORIZATION application; 

SET app_name.app_user = 'bob'; 

SELECT * FROM t1; 

id | f1 | app_user 
----+----+---------- 
    1 | a | bob 
(1 row) 

SET app_name.app_user = 'alice'; 
SELECT * FROM t1; 

id | f1 | app_user 
----+----+---------- 
    2 | b | alice 
(1 row) 

SET app_name.app_user = 'none'; 
SELECT * FROM t1; 

id | f1 | app_user 
----+----+---------- 
(0 rows) 

:コメント欄でa_horse_with_no_nameのリンクから


更新(おかげで、そのスレッドは上のスポットです)これは設定パラメータのためのものだと感じています... app_nameはどこに定義されていますか?セッションの設定に基づいてセキュリティポリシーを設定する

+2

http://www.postgresql.org/message-id/[email protected] –

+0

@a_horse_with_no_name - ありがとうございました。しかし、スレッドで与えられた例はちょっと暗いです...私は質問を更新しました。 – losthorse

+0

**設定パラメータの**は**です。これを使用することは、本質的に「ハック」です。これを事前に定義する必要はありません。これは動的に行うことができます。パラメータが定義されていない場合、 'current_setting( 'app_name.app_user')'はエラーになります。これを防ぐため、 'postgresql.conf'にダミー値を定義することができます。 –

答えて

6

は(私は、私はそれを意味することを私を信頼CAPSと大胆両方を憎む)BAD BAD BADアイデアです。 任意のユーザSET SESSION 'app_name.app_user' = 'bob'です。だから誰かが "app_name.app_user"がドアに入っていると思うと(信じてくれれば)、あなたのセキュリティ全体がドアの外に出ています。

私が見る唯一の方法は、セッショントークンを(uuidタイプが頭に浮かぶ、使いやすさのためにtextにキャスト)格納するだけで、あなたのwebadminにアクセス可能なテーブルを使用することです。 login()の機能はSECURITY DEFINER(所有者がwebadminと仮定)、トークンとセッションSETが設定されているとし、webadminが所有している(または適切な特権を持つ)テーブルがそのテーブルとそのポリシーのセッション設定を参照します。

残念なことに、一時テーブルにポリシーを作成できないため、「実」テーブルを使用する必要があるため、一時的(セッション)テーブルを使用することはできません。

CREATE FUNCTION login (uname text, pwd text) RETURNS boolean AS $$ 
DECLARE 
    t uuid; 
BEGIN 
    PERFORM * FROM users WHERE user = uname AND password = pwd; 
    IF FOUND THEN 
    INSERT INTO sessions SET token = uuid_generate_v4()::text, user .... 
     RETURNING token INTO t; 
    SET SESSION "app_name.token" = t; 
    RETURN true; 
    ELSE 
    SET SESSION "app_name.token" = ''; 
    RETURN false; 
    END IF; 
END; $$ LANGUAGE plpgsql STRICT; 

そして今、あなたのポリシーは、リンクするsessionsへ:

CREATE POLICY p ON t1 FOR SELECT 
    USING (SELECT true FROM sessions WHERE token = current_setting('app_name.token')); 

それは実際には

...パフォーマンスペナルティのようなものですが、ハックの損傷に対することを量ります(uuidはユニークであると仮定できるので、LIMIT 1の注文やその他の魔法の必要はありません。uuidがテーブルにある場合、ポリシーは合格し、それ以外の場合は失敗します。)uuidは(あなたの生涯内にとにかく)推測することは不可能であり、誰でも検索することは不可能ですが、webadminです。

+0

これは完全に正確ではありません。ポリシーは特定のロールに指定できるので、例では、webadminロールのみに対してポリシーを作成し、app_name.app_user GUCを設定すると、そのロールが発行するクエリにのみ影響します。それはあなたのセキュリティ要件には十分であるかもしれませんが、GUCを変更することで、「すべてのユーザー」がテーブルのレコードにアクセスできなくなります。これは、 "webadmin"ロールを使用するアプリケーションが適切にユーザーを検証し、SQLインジェクションのバグがないことを必要とします。 –

+2

[2象限](http://blog.2ndquadrant.com/application-users-vs-row-level-security/)には、暗号化署名を使用して、ユーザーがバイパスできない方法で許可を管理する例があります。 – spiffytech

関連する問題