Polyinstantiationの誘惑(2)

Polyinstantiation化したテーブルを考える上で、Foreign keyの使い方は厄介である。

そもそも Polyinstantiation の目的は、制約条件を本来の意図とは異なる方法で利用される事により機密レベルの高い情報が漏洩することを防ぐことにある。したがって、Primay key制約と同様に、Foreign key制約を利用した攻撃に対処する必要がある。

以下のようなケースを考えてみる。

Table: flight
| level        | flight | destination |
+--------------+--------+-------------+
| Unclassified |'A123'  | 'Narita'    |
| Secret       |'J004'  | 'Haneda'    |
+--------------+--------+-------------+

Table: passenger
| level        | name    | flight |seat|
+--------------+---------+--------+----+
| Unclassified |'KaiGai' | 'J004' | 'E'|
| Classified   |'ymj'    | 'J004' | 'E'|
| Classified   |'tak'    | 'A123' | 'B'|
+--------------+---------+--------+----+

flightテーブルのprimary keyはflightで、passengerテーブルのflightはForeign keyである。
神の視点から眺めた場合、このテーブルの構成は正しい。しかし、仮にClassifiedユーザの視点から眺めた場合、おかしなことになる。行レベルアクセス制御によって、'Haneda'行きのフライト'J004'は隠される。しかし、passengerテーブルにはClassifiedユーザから可視なユーザ'KaiGai'や'ymj'がこの'J004'便を参照している。
passenger.flight → flight.flight という外部キーが存在することから、Classifiedユーザは容易に'J004'という便が存在していることを知ることができる。したがって、これは Secret → Classified への隠しチャネルであるということになる。

これを防ぐために、Polyinstantiation化されたテーブルに対するForeign key制約に対して以下の追加的な制約を加える必要がある。
LEVEL(FK) ≧ LEVEL(PK)
外部キーの機密レベルが常にPrimary keyより高くなければならないという制約を新たに追加することで、前述の問題は回避される。なぜなら、Foreign keyを可視なプロセスは全てPrimary keyも可視だからである。

一方逆のケースを考える。
先ほどのテーブルで、Unclassifiedユーザがfilghtテーブルの'A123'のタプルを削除しようとした場合、彼にはこの操作は許可されるものと見えるだろう。なぜなら、'A123'を参照しているのは'tak'のみであり、Unclassifiedユーザからは不可視だからである。
しかし、Unclassifiedユーザが'A123'タプルの削除を妨げられてはならない。なぜなら、'A123'タプルを*削除できない*ことにより、彼は passenger テーブルに少なくとも一個以上の 'A123' を参照しているより機密レベルの高いタプルが存在していることに気が付くからである。
この問題に対処する方法は2つある。一つは、先ほどの制約条件をさらに強めて
LEVEL(FK) = LEVEL(PK)
を常に満足するようにするもの。これは非常にシンプルであるが、柔軟さに欠ける対処方法である。しかし、機密レベルを揃える事で、片方が可視で片方が不可視という状況を常に避けることができる。
もう一つは大胆な解決方法で、RESTRICT型の Foreign key を設定させないことである。Foreign keyには他にもCASCADE, SET NULL, SET DEFAULTの3つの形式で制約を設定することが可能で、この場合、Primary key側を削除しても機密レベルの低いユーザには情報は伝達されない。

この話、まだ続きます。

あと、明日ちょっとしたニュースリリースがある予定。