ルールと権限

PostgreSQL 9.1.1文書
前のページ | 巻戻し | 第 37章ルールシステム | 早送り | 次のページ

# 37.4. ルールと権限

PostgreSQLのルールシステムによる問い合わせの書き換えによって、オリジナルの問い合わせで使われたものではない他のテーブル/ビューがアクセスされます。 更新ルールを使うことによってテーブルへの書き込みアクセスを包含することができます。

書き換えルールに別々の所有者はいません。 リレーション（テーブルまたはビュー）の所有者は自動的にそれに定義された書き換えルールの所有者となります。 PostgreSQLのルールシステムはデフォルトのアクセス制御システムの振舞いを変更します。 ルールによって使用されるリレーションは、ルールを起動したユーザの権限ではなく、ルール所有者の権限でチェックされます。 このことは、ユーザは問い合わせで明記するテーブル/ビューに対しての権限だけあればよいことを示しています。

例えば、以下のようにします。 あるユーザが、いくつかは個人用の、その他は事務所で秘書が利用するための、電話番号のリストを持っていたとします。 ユーザは次のようにして構築することができます。

    CREATE TABLE phone_data (person text, phone text, private boolean);
    CREATE VIEW phone_number AS
        SELECT person, CASE WHEN NOT private THEN phone END AS phone
        FROM phone_data;
    GRANT SELECT ON phone_number TO secretary;

そのユーザ（とデータベースのスーパーユーザ）以外は`phone_data`テーブルにアクセスできません。 しかし、`GRANT`により秘書は`phone_number`ビューに対し`SELECT`できます。 ルールシステムは`phone_number`からの`SELECT`操作を`phone_data`からの`SELECT`操作に書き換えます。 そのユーザは`phone_number`の所有者、したがってルールの所有者ですから、`phone_data`の読み込みに対するアクセスはそのユーザの権限に従ってチェックされ、問い合わせを受け付けてもよいことになります。 `phone_number`へのアクセスもチェックされますが、これは呼び出したユーザに対して行われますので、秘書とユーザ以外は使うことができません。

権限はルールごとにチェックされます。 ですから秘書だけが今のところ公開の電話番号を参照することができます。 しかし、秘書は別のビューを作成し、それにPUBLICに対するアクセス許可を与えることができます。 こうすると秘書のビューを通して誰もが`phone_number`データを見ることができます。 秘書ができないことは`phone_data`に直接アクセスするビューを作ることです （実際には作成はできますが、アクセスは全て、権限チェックで拒絶されます）。 そして、秘書が独自の`phone_number`ビューを開いたことにユーザが気付いた時点で、秘書の権限を取り上げることができます。 秘書のビューへのアクセスは即座に失敗に終わります。

このルールごとのチェックがセキュリティホールになると考える人がいるかもしれませんが、実際にはそうではありません。 もしこのように機能しないとなると、秘書は`phone_number`と同じ列を持ったテーブルを用意して、1日1回データをそこにコピーするかもしれません。 そうなると、データは彼のものですから、誰にアクセス権を与えようが彼の自由です。 `GRANT`は"あなたを信用しています"ということです。 信用している誰かがこのようなことを行った場合は、考えを変えて`REVOKE`してください。

上に示したような手法を使ってある列の内容を隠すのにビューは使えますが、見えない行にあるデータを信頼して隠すのには使えないことに注意してください。 例えば、以下のビューは安全ではありません。

    CREATE VIEW phone_number AS
        SELECT person, phone FROM phone_data WHERE phone NOT LIKE '412%';

ルールシステムが`phone_number`からの`SELECT`を`phone_data`からの`SELECT`に書き換え、`phone`が412で始まらない項目のみが必要だという条件を追加しますので、このビューは安全に見えます。 しかし、ユーザが自身の関数を作成できるのであれば、`NOT LIKE`式の前にユーザ定義の関数を実行するようプランナを説得することは難しくありません。 例えば以下の通りです。

    CREATE FUNCTION tricky(text, text) RETURNS bool AS $$
    BEGIN
        RAISE NOTICE '% => %', $1, $2;
        RETURN true;
    END
    $$ LANGUAGE plpgsql COST 0.0000000000000000000001;

    SELECT * FROM phone_number WHERE tricky(person, phone);

プランナはより高価な`NOT LIKE`の前に安価な`tricky`関数を実行することを選びますので、`phone_data`テーブルの人と電話番号はすべて`NOTICE`として表示されます。 たとえユーザが新しい関数を定義できない場合でも、同様の攻撃で組み込み関数が使えます。 （例えば、ほとんどの型変換関数は生成するエラーメッセージを入力値に含んでいます。）

同様の考慮は更新ルールにも適用できます。 前節の例において、データベースのテーブルの所有者は`shoelace`ビューに対し、誰かに`SELECT`、`INSERT`、`UPDATE`、`DELETE`権限を与えることができます。 しかし、`shoelace_log`に対しては`SELECT`だけです。 ログ項目を書き込むルールアクションは支障なく実行され、また、他のユーザはログ項目を見ることができます。 しかし、他のユーザは項目を捏造したり、既に存在する項目を操作する、あるいは削除することはできません。 この場合、`shoelace_log`を参照しているルールは条件のない`INSERT`だけですので、操作の順序を変えるようにプランナを説得することでルールを破壊する可能性はありません。 これはより複雑な状況では正しくないかもしれません。

前のページ | ホーム | 次のページ
`INSERT`、`UPDATE`、`DELETE`についてのルール | 上に戻る | ルールおよびコマンドの状態