11 Oracle Virtual Private Databaseを使用したデータ・アクセスの制御

Oracle Virtual Private Database (VPD)を使用すると、データにアクセスするユーザーをフィルタ処理できます。

11.1 Oracle Virtual Private Databaseについて

Oracle Virtual Private Database (VPD)には、ユーザーによるデータへのアクセスをフィルタ処理する場合の重要なメリットがあります。

11.1.1 Oracle Virtual Private Database

Oracle Virtual Private Database(VPD)で、行および列レベルでデータベース・アクセスを制御するセキュリティ・ポリシーを作成します。

ノート:

Oracle Databaseリリース12cでは、VPDにかわってReal Application Security (RAS)が採用されました。アプリケーションで行レベルおよび列レベルのアクセス制御が必要な新規プロジェクトにはRASを使用することをお薦めします。

基本的には、Oracle Virtual Private Databaseのセキュリティ・ポリシーが適用された表、ビューまたはシノニムに対して発行されるSQL文に、動的なWHERE句が追加されます。

Oracle Virtual Private Databaseを使用すると、データベース表、ビューまたはシノニムに対するセキュリティを直接詳細なレベルまで規定できます。これらのデータベース・オブジェクトにセキュリティ・ポリシーを直接付加すると、ユーザーがデータにアクセスするたびにポリシーが自動的に適用されるため、セキュリティを回避できません。

ユーザーがOracle Virtual Private Databaseポリシーで保護されている表、ビューまたはシノニムに直接的または間接的にアクセスすると、Oracle DatabaseはユーザーのSQL文を動的に変更します。この変更は、セキュリティ・ポリシーを実装する関数によって戻されたWHERE条件(述語)に基づいて行われます。Oracle Databaseでは、関数内に記述された条件、または関数が戻す条件を使用して、動的かつユーザーに対して透過的に文が変更されます。Oracle Virtual Private Databaseポリシーは、SELECTINSERTUPDATEINDEXおよびDELETE文に適用できます。

たとえば、ユーザーが次の問合せを実行するとします。

SELECT * FROM OE.ORDERS;

Oracle Virtual Private Databaseポリシーにより、WHERE句の文が動的に追加されます。例:

SELECT * FROM OE.ORDERS 
 WHERE SALES_REP_ID = 159;

この例では、ユーザーは営業担当者159の受注のみを表示できます。

このユーザーのセッション情報(ユーザーのIDなど)に基づいてユーザーをフィルタ処理する場合は、WHERE句を作成してアプリケーション・コンテキストを使用できます。例:

SELECT * FROM OE.ORDERS 
 WHERE SALES_REP_ID = SYS_CONTEXT('USERENV','SESSION_USER'); 

ノート:

Oracle Virtual Private Databaseでは、DDL(TRUNCATE文やALTER TABLE文)のフィルタ処理はサポートされていません。

11.1.2 Oracle Virtual Private Databaseポリシーを使用するメリット

Oracle Virtual Private Databaseポリシーには、重要なメリットがあります。

11.1.2.1 アプリケーションではなくデータベース・オブジェクトに基づくセキュリティ・ポリシー

Oracle Virtual Private Databaseにはセキュリティ、簡易性、柔軟性という利点があります。

すべてのアプリケーションでアクセス制御を実装するのではなく、Oracle Virtual Private Databaseセキュリティ・ポリシーをデータベース表、ビューまたはシノニムに付加すると、次のようなメリットがあります。

  • セキュリティ。データベース表、ビューまたはシノニムにポリシーを対応付けることで、アプリケーション・セキュリティの重大な問題を解決できます。たとえば、アプリケーションの使用を許可されているユーザーが、そのアプリケーションに対応付けられている権限を利用し、SQL*Plusなどの非定型の問合せツールを使用してデータベースを誤って変更してしまう可能性があります。ファイングレイン・アクセス・コントロールでは、セキュリティ・ポリシーを表、ビューまたはシノニムに直接付加することによって、ユーザーがどのような方法でデータにアクセスしても、同じセキュリティが施行されます。

  • 簡潔性。セキュリティ・ポリシーは、表ベース、ビュー・ベースまたはシノニム・ベースのアプリケーションごとに繰り返し追加するのではなく、表、ビューまたはシノニムに1回のみ追加します。

  • 柔軟性。SELECT文には1つのセキュリティ・ポリシーを、INSERT文には別のポリシーを、さらにUPDATE文およびDELETE文にはまた別のポリシーを指定できます。たとえば、人事部門の担当者には、その部門内のすべての社員のレコードに対するSELECT権限を付与し、名字がAからFで始まるその部門内の社員の給与のみを更新できるように指定できます。さらに、各表、ビューまたはシノニムに対して複数のポリシーを作成できます。

11.1.2.2 Oracle Databaseによるポリシー関数の評価方法の制御

ポリシー関数を複数回実行すると、パフォーマンスに影響を与える可能性があります。

Oracle DatabaseがOracle Virtual Private Database述語をキャッシュする方法を構成することによって、ポリシー関数のパフォーマンスを制御できます。

次のオプションを使用できます。

  • 各問合せについてポリシーを1回評価します(静的ポリシー)。

  • ポリシー関数内のアプリケーション・コンテキストが変更された場合のみ、ポリシーを評価します(状況依存ポリシー)。

  • 実行ごとにポリシーを評価します(動的ポリシー)。

11.1.3 Oracle Virtual Private Databaseポリシーの作成者とは

DBMS_RLS PL/SQLパッケージでは、VPDポリシーを作成できます。

DBMS_RLS PL/SQLパッケージのEXECUTE権限が付与されたユーザーは、Oracle Virtual Private Databaseポリシーを作成できます。すべての権限と同様、この権限は信頼できるユーザーにのみ付与してください。ユーザーに付与された権限を確認するには、DBA_SYS_PRIVSデータ・ディクショナリ・ビューに問い合せます。

11.1.4 Oracle Virtual Private Databaseポリシー関数を実行するための権限

Oracle Virtual Private Database (VPD)ポリシー関数を実行するには、正しい権限を使用する必要があります。

セキュリティを強化するために、Oracle Virtual Private Database ポリシー関数は、定義者権限で宣言されたかのように実行されます。

実行者権限として宣言すると、自分自身だけでなく、コードをメンテナンスする他のユーザーも混乱させてしまうため、実行者権限では宣言しないでください。

関連項目:

定義者権限の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

11.1.5 Oracle Virtual Private Databaseでのアプリケーション・コンテキストの使用

Oracle Virtual Private Databaseポリシーを使ったアプリケーション・コンテキストを使用できます。

アプリケーション・コンテキストを作成すると、ユーザー情報が安全にキャッシュされます。キャッシュ環境を設定できるのは、指定されたアプリケーション・パッケージのみです。ユーザーやパッケージ外部からの変更はできません。さらに、データがキャッシュされるため、パフォーマンスが向上します。

たとえば、ORDERS_TAB表へのアクセスを顧客ID番号を基にして行うとします。顧客ID番号が必要になるたびにログインしたユーザーに問い合せるのではなく、アプリケーション・コンテキスト内に顧客ID番号を格納しておくことができます。このようにすると、顧客番号は必要なときにセッションで使用できます。

アプリケーション・コンテキストは、セキュリティ・ポリシーが複数のセキュリティ属性に基づく場合に特に役立ちます。たとえば、WHERE述語が4つの属性(従業員番号、コスト・センター、職位、支出制限など)に基づくポリシー関数は、この情報を取得するために複数の副問合せを実行する必要があります。このデータがアプリケーション・コンテキストを介して使用可能な場合、パフォーマンスは大きく向上します。

アプリケーション・コンテキストを使用すると、述語により規定される正しいセキュリティ・ポリシーを戻すことができます。たとえば、「顧客は自分の注文のみを参照でき、社員はすべての顧客のすべての注文を参照できる」というルールを規定している受注管理アプリケーションを想定します。この場合は、2つの異なるポリシーがあります。position属性でアプリケーション・コンテキストを定義できます。この属性はポリシー関数内でアクセスでき、その属性の値に基づいて正しい述語を戻します。そのため、職位がclerk (社員)であるユーザーはすべての注文を取得できるようにし、customer (顧客)であるユーザーは自分に関連するレコードのみ参照できるようにすることができます。

属性に対して特定の述語を戻すファイングレイン・アクセス・コントロール・ポリシーを設計するには、ポリシーを実装する関数内でアプリケーション・コンテキストにアクセスする必要があります。たとえば、顧客が自分のレコードのみを参照するように制限する必要があるとします。ユーザーは次の問合せを実行します。

SELECT * FROM orders_tab

ファイングレイン・アクセス・コントロールによって、この問合せはWHERE述語が含まれるように動的に変更されます。

SELECT * FROM orders_tab 
  WHERE custno = SYS_CONTEXT ('order_entry', 'cust_num');

前述の例で、50,000人の顧客が存在し、各顧客が受け取る述語を同じにするとします。すべての顧客は同一のWHERE述語を共有し、自分の注文のみを参照できます。顧客間で異なるのは、顧客番号のみです。

アプリケーション・コンテキストを使用して、50,000人の顧客に適用されるポリシー関数内で1つのWHERE述語を返すことができます。結果として、顧客番号が実行時に評価されるため、顧客ごとに実行方法が異なる1つの共有カーソルが存在することになります。この値は、すべての顧客で異なります。このようにアプリケーション・コンテキストを使用することで、最適なパフォーマンスと行レベルのセキュリティが実現します。

SYS_CONTEXT関数がバインド変数のように動作するのは、SYS_CONTEXT引数が定数の場合のみです。

11.1.6 マルチテナント環境でのOracle Virtual Private Database

アプリケーション・ルートで仮想プライベート・データベース・ポリシーを作成して、関連付けられたすべてのアプリケーションPDBで使用できます。

CDBの制限は、共有の状況依存ポリシーのほか、仮想プライベート・データベース・ポリシー関連のビューにも適用されます。マルチテナント環境全体に仮想プライベート・データベース・ポリシーを作成することはできません。

アプリケーション・コンテナについては、仮想プライベート・データベース・ポリシーを作成して、アプリケーション・ルートに属するすべてのPDBに共通ポリシーを適用することで、アプリケーション共通オブジェクトを保護できます。つまり、アプリケーション・ルートにアプリケーションをインストールすると、共通オブジェクトを保護するすべての共通仮想プライベート・データベース・ポリシーは、アプリケーション・コンテナのすべてのPDBに適用され、即座に実施されます。

次のことに注意してください。

  • アプリケーション・ルートでは共通仮想プライベート・データベース・ポリシーおよびそれに関連するPL/SQLファンクションのみを作成し、それをアプリケーション共通オブジェクトに付加することができます。ファンクションがポリシーと同じ場所にない場合、実行時にエラーが発生します。

  • 共通オブジェクトに適用される仮想プライベート・データベース・ポリシーは、アプリケーションPDBからアプリケーション共通オブジェクトにアクセスする場合、アプリケーション・コンテナに属するPDBで自動的に強制される共通ポリシーと見なされます。

  • アプリケーション共通仮想プライベート・データベース・ポリシーは、アプリケーション共通オブジェクトのみを保護できます。

  • アプリケーション・ルートのアプリケーション共通オブジェクトに適用され、すべてのアプリケーションPDBに適用される仮想プライベート・データベース・ポリシーは、共通仮想プライベート・データベース・ポリシーと見なされます。ローカル・データベース表に適用され、1つのPDBで実施されるポリシーは、ローカル仮想プライベート・データベース・ポリシーと見なされます。

    たとえば、ポリシーVPD_P1がアプリケーション・ルートのアプリケーション共通表T1に適用される場合は、共通ポリシーと見なされます。このポリシーは各アプリケーションPDBに強制されます。VPD_P1というポリシーがPDB1T1というローカル表に適用される場合は、ローカル・ポリシーと見なされ、PDB1のみがその影響を受けます。VPD_P1というポリシーがアプリケーション・ルートのT1というローカル表に適用される場合も、アプリケーション・ルートのみが影響を受けるため、ローカル・ポリシーと見なされます。この概念は、仮想プライベート・データベース・ポリシーの有効化、無効化および削除などの他の操作にも適用されます。

  • アプリケーション共通仮想プライベート・データベース・ポリシーはアプリケーション共通オブジェクトのみを保護し、ローカル仮想プライベート・データベース・ポリシーはローカル・オブジェクトのみを保護します。

  • アプリケーション・コンテキストを使用している場合は、共通データベース・セッション・ベースのアプリケーション・コンテキストおよび共通グローバル・アプリケーション・コンテキスト・オブジェクトを共通仮想プライベート・データベース構成で使用するようにしてください。

  • アプリケーション・コンテナの仮想プライベート・データベース・ポリシーは、アプリケーション・ルートに格納されます。PDBにはローカル・ポリシーのみが格納されます。PDBをアプリケーション・コンテナに接続する場合、共通ポリシーはローカル・ポリシーに変換されません。かわりに、Oracle Databaseがアプリケーション・ルートからそれらをロードし、ポリシーからローカルPDBの共通オブジェクトにアクセスがあると、ローカルPDBでそれらを強制します。

11.2 Oracle Virtual Private Databaseポリシーのコンポーネント

VPDポリシーは関数を使用して動的WHERE句を生成し、ポリシーを使用して保護するオブジェクトに関数を付加します。

11.2.1 動的なWHERE句を生成する関数

Oracle Virtual Private Database (VPD)関数で、適用する制限を定義します。

Oracle Virtual Private Database (VPD)の動的なWHERE句(述語)を生成するには、これらの制限を定義した関数(プロシージャではなく)を作成する必要があります。この関数は、定義者権限関数です。

通常は、セキュリティ管理者が自分のスキーマにこの関数を作成します。別の関数のコールを含めたり、ログイン失敗を追跡するためのチェックを追加するなど、複雑な動作が必要な場合は、これらの関数を1つのパッケージ内に作成します。

関数では、次の動作が必要です。

  • 引数としてスキーマ名、入力としてオブジェクト(表、ビューまたはシノニム)名を取る必要があります。これらの情報を保持するように入力パラメータを定義しますが、関数内でスキーマ名とオブジェクト名自体を指定しないでください。DBMS_RLSパッケージ(保護するオブジェクトに関数を付加するポリシーを参照)を使用して作成したポリシーによって、スキーマ名、およびポリシーが適用されるオブジェクトが提供されます。最初にスキーマのパラメータを作成し、その後にオブジェクトのパラメータを作成する必要があります。

  • 生成するWHERE句述語の戻り値を提供する必要があります。WHERE句の戻り値は、常にVARCHAR2データ型です。

  • 有効なWHERE句を生成する必要があります。このコードは、例: 単純なOracle Virtual Private Databaseポリシーの作成に示すように基本的なもので、WHERE句はログインするすべてのユーザーに共通です。

    ただし、ほとんどの場合、各ユーザー、ユーザーの各グループ、または保護するオブジェクトにアクセスする各アプリケーションに異なるWHERE句を設計する必要があります。たとえば、マネージャがログインする場合は、そのマネージャの権限に固有のWHERE句を生成できます。これを行うには、ユーザー・セッション情報にアクセスするアプリケーション・コンテキストをWHERE句の生成コードに組み込みます。チュートリアル: セッション・ベースのアプリケーション・コンテキスト・ポリシーの実装では、アプリケーション・コンテキストを使用するOracle Virtual Private Databaseポリシーの作成方法について説明します。

    アプリケーション・コンテキストを使用しないOracle Virtual Private Database関数を作成することもできますが、アプリケーション・コンテキストを使用すると、ユーザーのセッション属性(ユーザーIDなど)に基づいてユーザー・アクセスが安全に行われるため、より強固なOracle Virtual Private Databaseポリシーを作成できます。様々なタイプのアプリケーション・コンテキストの詳細は、「アプリケーション・コンテキストを使用したユーザー情報の取得」を参照してください。

    さらに、CまたはJavaコールを埋め込み、オペレーティング・システム情報にアクセスしたり、オペレーティング・システム・ファイルや他のソースからWHERE句を戻すことができます。

  • 関連するポリシー関数内の表から選択しないでください。表へのポリシーの定義は可能ですが、表に定義されたポリシーから表を選択することはできません。

  • 純粋関数である必要があります。VPD関数は、受け取ったアプリケーション・コンテキストおよび引数のみに依存して、WHERE句を生成するものでなければなりません。この関数がパッケージ変数に依存することは許可されません。

ノート:

関数を様々なエディションで実行する場合、関数の結果がすべてのエディションで同一か、または関数が実行されているエディションによって異なるかに関係なく、関数の結果を制御できます。詳細は、エディションがグローバル・アプリケーション・コンテキストのPL/SQLパッケージの結果に与える影響を参照してください。

11.2.2 保護するオブジェクトに関数を付加するポリシー

Oracle Virtual Private Databaseポリシーで、VPD関数を表やビュー、シノニムに関連付けます。

このポリシーを作成するには、DBMS_RLSパッケージを使用します。SYSでない方は、DBMS_RLSパッケージを使用するためにEXECUTE権限を付与される必要があります。このパッケージには、ポリシーの管理とファイングレイン・アクセス・コントロールの設定が可能になるプロシージャが含まれています。たとえば、ポリシーを表に付加するには、DBMS_RLS.ADD_POLICYプロシージャを使用します。この設定の中で、たとえばユーザーがSELECT文やUPDATE文を表またはビューで発行するとポリシーが有効になるよう設定して、ファイングレイン・アクセス・コントロールを設定します。

Oracle Virtual Private Databaseポリシーの作成とは、関数を作成し、その関数を表またはビューに適用することを意味します。

11.3 Oracle Virtual Private Databaseのポリシーの構成

DBMS_RLS PL/SQLパッケージで、Oracle Virtual Private Database (VPD)ポリシーを構成できます。

11.3.1 Oracle Virtual Private Databaseポリシーについて

Oracle Virtual Private Databaseポリシーで、VPD関数をデータベース表やビュー、シノニムに関連付けます。

この関数はOracle Virtual Private Database WHERE句のアクションを定義します。この関数を、Oracle Virtual Private Database (VPD)アクションが適用されるデータベース表に関連付ける必要があります。

これを行うには、Oracle Virtual Private Databaseポリシーを構成します。ポリシーとは、仮想プライベート・データベース関数を管理するメカニズムです。また、ポリシーを使用すると、ファイングレイン・アクセス・コントロールを追加できるため、たとえば、SQL文のタイプを指定したり、特定の表列にポリシーを適用できます。ユーザーがこのデータベース・オブジェクト内のデータにアクセスすると、ポリシーが自動的に有効になります。

表11-1に、DBMS_RLSパッケージに含まれているプロシージャを示します。

表11-1 DBMS_RLSのプロシージャ

プロシージャ 説明

個別ポリシーの処理用

-

DBMS_RLS.ADD_POLICY

表、ビューまたはシノニムにポリシーを追加します。

DBMS_RLS.ENABLE_POLICY

表、ビューまたはシノニムに事前に追加したポリシーを使用可能または使用禁止にします。

DBMS_RLS.ALTER_POLICY

属性とポリシーの関連付けまたは関連付けの解除のため、既存のポリシーを変更します。

DBMS_RLS.REFRESH_POLICY

静的ポリシー以外のポリシーに対応付けられたカーソルを無効にします。

DBMS_RLS.DROP_POLICY

表、ビューまたはシノニムからポリシーを削除します。

グループ・ポリシーの処理用

-

DBMS_RLS.CREATE_POLICY_GROUP

ポリシー・グループを作成します。

DBMS_RLS.ALTER_GROUPED_POLICY

ポリシー・グループを変更します。

DBMS_RLS.DELETE_POLICY_GROUP

ポリシー・グループを削除します。

DBMS_RLS.ADD_GROUPED_POLICY

特定のポリシー・グループにポリシーを追加します。

DBMS_RLS.ENABLE_GROUPED_POLICY

グループ内のポリシーを使用可能にします。

DBMS_RLS.REFRESH_GROUPED_POLICY

リフレッシュされたポリシーに対応付けられたSQL文を再解析します。

DBMS_RLS.DISABLE_GROUPED_POLICY

グループ内のポリシーを使用禁止にします。

DBMS_RLS.DROP_GROUPED_POLICY

特定のグループに属するポリシーを削除します。

アプリケーション・コンテキストの処理用

-

DBMS_RLS.ADD_POLICY_CONTEXT

アクティブなアプリケーションのコンテキストを追加します。

DBMS_RLS.DROP_POLICY_CONTEXT

アプリケーションのコンテキストを削除します。

11.3.2 データベース表、ビューまたはシノニムへのポリシーの付加

DBMS_RLS PL/SQLパッケージで、表、ビューまたはシノニムにポリシーを付加できます。

  • ポリシーをデータベース表、ビューまたはシノニムに付加するには、DBMS_RLS.ADD_POLICYプロシージャを使用します。

ポリシーを追加する表、ビューまたはシノニム、およびポリシーの名前を指定する必要があります。また、ポリシーが制御する文のタイプ(SELECTINSERTUPDATEDELETECREATE INDEXまたはALTER INDEX)など、その他の情報も指定できます。

次のガイドラインに従ってください。

  • 拡張データリンク・オブジェクトとしてビューを作成した場合は、ビューの基礎となるオブジェクトの場合と同じVPDポリシーをこのタイプのビュー適用することをお薦めします。

  • VPDポリシーを追加するベース・オブジェクトに依存オブジェクトが含まれているかどうかを判別します。依存オブジェクトが含まれている場合は、そのVPDポリシーがベース・オブジェクトに追加されるとこれらのオブジェクトは無効になり、使用時には自動的に再コンパイルされます。

    あるいは、ALTER ... COMPILE文を使用してこれらを各自でプロアクティブに再コンパイルできます。依存オブジェクトを(そのベース・オブジェクトにVPDポリシーを追加することにより)を無効にすると、それらを再コンパイルする必要が生じ、これが原因でシステム全体のパフォーマンスが低下する可能性がある点に注意してください。依存オブジェクトが含まれるオブジェクトにVPDポリシーを追加する操作は、オフピーク時またはスケジュールされた停止時間のみに行うことをお薦めします。

  • 1つのオブジェクトに作成できるポリシーの最大数は255であることに注意してください。

11.3.3 例: 表への単純なOracle Virtual Private Databaseポリシーの付加

DBMS_RLS.ADD_POLICYプロシージャで、Oracle Virtual Private Database (VPD)ポリシーを表、ビューまたはシノニムに付加できます。

例11-1に、DBMS_RLS.ADD_POLICYを使用して、secure_updateというOracle Virtual Private DatabaseポリシーをHR.EMPLOYEES表に付加する方法を示します。ポリシーに付加される関数はcheck_updatesです。

例11-1 表への単純なOracle Virtual Private Databaseポリシーの付加

BEGIN
 DBMS_RLS.ADD_POLICY(
  object_schema   => 'hr',
  object_name     => 'employees',
  policy_name     => 'secure_update',
  policy_function => 'check_updates',
...

関数がパッケージ内に作成されている場合は、パッケージ名を指定します。例:

 policy_function => 'pkg.check_updates',
...

表へのポリシーの定義は可能ですが、表に定義されたポリシーから表を選択することはできません。

11.3.4 特定のSQL文に対するポリシーの規定

Oracle Virtual Private Databaseポリシーは、SELECTINSERTUPDATEINDEXおよびDELETE文に規定できます。

  • ポリシーに対してSQL文のタイプを指定するには、DBMS_RLS.ADD_POLICYプロシージャのstatement_typesパラメータを使用します。複数指定するには、それぞれをカンマで区切ります。リストは一重引用符で囲みます。

文のタイプを指定しない場合、Oracle DatabaseではデフォルトでSELECTINSERTUPDATEおよびDELETEが指定されますが、INDEXは指定されません。これらの文のタイプの組合せを入力できます。

statement_typesパラメータを指定する場合は、次の機能に注意してください。

  • Virtual Private Databaseポリシーによる影響を受けるアプリケーション・コードとして、MERGE INTO文が含まれる場合があります。しかし、Virtual Private Databaseポリシーでは、statement_typesパラメータにINSERTUPDATE、およびDELETEの3つの文すべてを含めてポリシーを正常に機能させる必要があります。あるいは、statement_typesパラメータを省略できます。

  • 索引をメンテナンスする権限を持っているユーザーは、たとえこのユーザーがSELECTのような標準問合せでは完全な表アクセスを持っていない場合でも、すべての行データを参照できることに注意してください。たとえばユーザーは、列値を引数とする、ユーザー定義関数を含む関数ベースの索引を作成できます。索引作成時に、Oracle Databaseがあらゆる行の列値をユーザー関数へ渡して、索引を作成するユーザーが行データを使用できるようにします。INDEXstatement_typesパラメータで指定することにより、Oracle Virtual Private Databaseポリシーを索引メンテナンス操作で適用できます。

11.3.5 例: DBMS_RLS.ADD_POLICYを使用したSQL文の指定

DBMS_RLS.ADD_POLICYプロシージャのstatement_typesパラメータで、ポリシーのSELECT文とINDEX文を指定できます。

例11-2に、これを行う方法を示します。

例11-2 DBMS_RLS.ADD_POLICYを使用したSQL文の指定

BEGIN
 DBMS_RLS.ADD_POLICY(
  object_schema   => 'hr',
  object_name     => 'employees',
  policy_name     => 'secure_update',
  policy_function => 'check_updates',
  statement_types => 'SELECT,INDEX');
END;
/

11.3.6 ポリシーを使用した列データ表示の制御

セキュリティに関連する列が問合せで参照される際に行レベルのセキュリティを規定するポリシーを作成できます。

11.3.6.1 列レベルのOracle Virtual Private Databaseのポリシー

列レベルのポリシーによって、セキュリティに関連する列が問合せで参照される際の行レベルのセキュリティを規定できます。

列レベルのOracle Virtual Private Databaseポリシーは、表やビューに適用できますが、シノニムには適用できません。ポリシーを列に適用するには、DBMS_RLS.ADD_POLICYプロシージャのSEC_RELEVANT_COLSパラメータを使用して、セキュリティ関連の列を指定します。このパラメータによって、問合せで列が明示的または暗黙的に参照されるたびに、セキュリティ・ポリシーが適用されます。

たとえば、人事部門以外のユーザーは、通常、各自の社会保障番号を参照することのみが許可されます。販売担当者が次の問合せを開始するとします。

SELECT fname, lname, ssn FROM emp;

セキュリティ・ポリシーを実装する関数は述語ssn='my_ssn'を戻します。Oracle Databaseは次のように問合せをリライトして実行します。

SELECT fname, lname, ssn FROM emp 
 WHERE ssn = 'my_ssn';
11.3.6.2 例: 列レベルのOracle Virtual Private Databaseポリシーの作成

CREATE FUNCTION文およびDBMS_RLS.ADD_POLICYプロシージャで、列レベルのOracle Virtual Private Databaseポリシーを構成できます。

例11-3は、営業部門(部門番号30)のユーザーは他部門の従業員の給与を参照できないというOracle Virtual Private Databaseポリシーを示します。このポリシーに関連する列は、salおよびcommです。最初にOracle Virtual Private Databaseポリシー関数を作成し、次にDBMS_RLS PL/SQLパッケージを使用して追加します。

例11-3 列レベルのOracle Virtual Private Databaseポリシーの作成

CREATE OR REPLACE FUNCTION hide_sal_comm (
 v_schema IN VARCHAR2, 
 v_objname IN VARCHAR2)

RETURN VARCHAR2 AS
con VARCHAR2 (200);

BEGIN
 con := 'deptno=30';
 RETURN (con);
END hide_sal_comm;

次に、DBMS_RLS.ADD_POLICYプロシージャを使用して、ポリシーを構成します。

BEGIN
 DBMS_RLS.ADD_POLICY (
  object_schema     => 'scott', 
  object_name       => 'emp',
  policy_name       => 'hide_sal_policy', 
  policy_function   => 'hide_sal_comm',
  sec_relevant_cols => 'sal,comm');
END;
11.3.6.3 問合せに関連する列の行のみの表示

デフォルトで、列レベルのOracle Virtual Private Databaseでは、機密情報が含まれた列が問合せで参照された場合、戻される行の数が制限されます。

これらのセキュリティ関連の列を指定するには、例11-3に示すように、DBMS_RLS.ADD_POLICYプロシージャのSEC_RELEVANT_COLUMNSパラメータを使用します。

たとえば、営業部門ユーザーはemp表に対してSELECT権限を持っており、この表は例11-3で作成された列レベルのOracle Virtual Private Databaseポリシーによって保護されている場合を想定します。ユーザー(たとえば、ユーザーSCOTT)は次の問合せを実行します。

SELECT ENAME, d.dname, JOB, SAL, COMM 
 FROM emp e, dept d
 WHERE d.deptno = e.deptno;

データベースは次の行を戻します。

ENAME      DNAME          JOB              SAL       COMM
---------- -------------- --------- ---------- ----------
ALLEN      SALES          SALESMAN        1600        300
WARD       SALES          SALESMAN        1250        500
MARTIN     SALES          SALESMAN        1250       1400
BLAKE      SALES          MANAGER         2850           
TURNER     SALES          SALESMAN        1500          0
JAMES      SALES          CLERK            950           
 
6 rows selected.

表示されるのは、行のすべての列に対してユーザーがアクセス権を持っている行のみです。

11.3.6.4 機密性の高い列をNULL値で表示するための列のマスク

問合せで機密性の高い列を参照する場合、デフォルトの列レベルのOracle Virtual Private Databaseでは、戻される行の数が制限されます。

列のマスク動作を利用すると、機密性の高い列を参照している場合にもすべての行が表示されます。ただし、機密性の高い列はNULL値で表示されます。列のマスク動作を有効にするには、DBMS_RLS.ADD_POLICYプロシージャのSEC_RELEVANT_COLS_optパラメータを設定します。

たとえば、前述の例に記載されている販売担当者の問合せ結果を考えてみます。列のマスクを使用すると、販売担当者自身の詳細と社会保障番号が格納されている行のみが表示されるのではなく、emp表からすべての行が表示されますが、ssn列の値はNULLになります。この動作は、行のサブセットのみを戻す他のあらゆるタイプのOracle Virtual Private Databaseポリシーとは基本的に異なることに注意してください。

列レベルのOracle Virtual Private Databaseに関するデフォルトのアクションとは対照的に、列のマスク動作ではすべての行が表示されますが、機密情報が含まれた列の値はNULLとして戻されます。ポリシーに列のマスク動作を含めるには、DBMS_RLS.ADD_POLICYプロシージャのSEC_RELEVANT_COLS_OPTパラメータをDBMS_RLS.ALL_ROWSに設定します。

列のマスクに関する考慮事項は次のとおりです。

  • 列のマスクが適用されるのは、SELECT文に対してのみです。

  • 通常のOracle Virtual Private Database述語とは異なり、ポリシー関数によって生成される列マスク条件は、単純なブール式であることが必要です。

  • 計算を実行するアプリケーションや、NULL値が戻されることが想定されていないアプリケーションの場合は、標準の列レベルのOracle Virtual Private Databaseを使用して、列のマスク動作オプションSEC_RELEVANT_COLS_OPTではなくSEC_RELEVANT_COLSを指定します。

  • オブジェクト・データ型(XMLtypeを含む)の列をsec_relevant_cols設定に含めないでください。この列型は、sec_relevant_cols設定ではサポートされていません。

  • UPDATE AS SELECTとともに使用される列のマスク動作によって更新されるのは、ユーザーが表示を許可されている列のみです。

  • 問合せによっては、列のマスク動作により一部の行が表示されない場合があります。例:

    SELECT * FROM emp
     WHERE sal = 10;
    

    列のマスク動作オプションが設定されているため、salary列にNULL値が戻される場合は、この問合せを実行しても行が戻されない場合があります。

11.3.6.5 例: Oracle Virtual Private Databaseポリシーへの列のマスクの追加

DBMS_RLS.ADD_POLICYプロシージャで、列レベルのOracle Virtual Private Database列のマスク動作を構成できます。

例11-4は、列レベルのOracle Virtual Private Database列のマスク動作を示しています。これは、例: 列レベルのOracle Virtual Private Databaseポリシーの作成と同じVPDポリシーを使用していますが、sec_relevant_cols_optDBMS_RLS.ALL_ROWSとして指定しています。

例11-4 Oracle Virtual Private Databaseポリシーへの列のマスクの追加

BEGIN
 DBMS_RLS.ADD_POLICY(
   object_schema         => 'scott', 
   object_name           => 'emp',
   policy_name           => 'hide_sal_policy', 
   policy_function       => 'hide_sal_comm',
   sec_relevant_cols     =>' sal,comm',
   sec_relevant_cols_opt => dbms_rls.ALL_ROWS);
END;

emp表に対するSELECT権限を持つ営業部門のユーザー(たとえば、SCOTT)が、次の問合せを実行するとします。

SELECT ENAME, d.dname, job, sal, comm 
 FROM emp e, dept d
 WHERE d.deptno = e.deptno;

データベースは、この問合せで指定されたすべての行を戻しますが、Oracle Virtual Private Databaseポリシーによって一部の値はマスクされています。

ENAME      DNAME          JOB              SAL       COMM
---------- -------------- --------- ---------- ----------
CLARK      ACCOUNTING     MANAGER
KING       ACCOUNTING     PRESIDENT
MILLER     ACCOUNTING     CLERK
JONES      RESEARCH       MANAGER
FORD       RESEARCH       ANALYST
ADAMS      RESEARCH       CLERK
SMITH      RESEARCH       CLERK
SCOTT      RESEARCH       ANALYST
WARD       SALES          SALESMAN        1250        500
TURNER     SALES          SALESMAN        1500          0
ALLEN      SALES          SALESMAN        1600        300
JAMES      SALES          CLERK            950           
BLAKE      SALES          MANAGER         2850           
MARTIN     SALES          SALESMAN        1250       1400
 
14 rows selected.

列のマスク動作により、営業部門のユーザーの問合せで要求された列がすべて戻されますが、営業部門以外の従業員に関してはsal列とcomm列がNULLになっています。

11.3.7 Oracle Virtual Private Databaseポリシー・グループ

Oracle Virtual Private Databaseポリシー・グループは、アプリケーションに適用できるVPDポリシーの名前付きコレクションです。

11.3.7.1 Oracle Virtual Private Databaseポリシー・グループについて

複数のセキュリティ・ポリシーをまとめてグループ化して、1つのアプリケーションに適用できます。

ポリシー・グループとは、アプリケーションに属する一連のセキュリティ・ポリシーです。有効なポリシー・グループを示すようにアプリケーション・コンテキスト(駆動コンテキストまたはポリシー・コンテキストと呼ばれます)を指定できます。ユーザーが表、ビュー、またはシノニム列にアクセスすると、Oracle Databaseが駆動コンテキストを検索して、有効なポリシー・グループを特定します。ポリシー・グループに属しているすべての関連ポリシーが適用されます。

ポリシー・グループは、複数のセキュリティ・ポリシーを持つ複数のアプリケーションが同一の表、ビューまたはシノニムを共有する場合に便利です。ポリシー・グループによって、表、ビューまたはシノニムがアクセスされたときに有効にするポリシーを識別できます。

たとえば、ホスト環境で、A社が、B社およびC社に対してBENEFIT表をホスティングするとします。この表は、2つの異なるセキュリティ・ポリシーを持つ、Human Resources(人事管理)およびFinance(財務管理)という2つアプリケーションによってアクセスされます。Human Resourcesアプリケーションは社内の序列に基づいてユーザーを認可し、Financeアプリケーションは部門に基づいてユーザーを認可します。これらの2つのポリシーをBENEFIT表に統合するには、2つの企業が共同でポリシーを開発する必要がありますが、それは現実的ではありません。ベース・オブジェクトに一連の特定のポリシーを規定するアプリケーション・コンテキストを定義することにより、各アプリケーションがセキュリティ・ポリシーの集合を個別に実装できます。

これを行うには、セキュリティ・ポリシーをグループ化します。アプリケーション・コンテキストを参照することにより、実行時に有効にするポリシーのグループをOracle Databaseが判断します。サーバーは、そのポリシー・グループに属するすべてのポリシーを規定します。

11.3.7.2 Oracle Virtual Private Databaseの新しいポリシー・グループの作成

DBMS_RLS.ADD_GROUPED_POLICYプロシージャで、VPDポリシーをVPDポリシー・グループに追加します。

有効にするポリシーを指定するには、DBMS_RLS.ADD_POLICY_CONTEXTプロシージャを使用して駆動コンテキストを追加できます。駆動コンテキストが不明なポリシー・グループを戻した場合は、エラーが戻されます。

駆動コンテキストが定義されていない場合は、すべてのポリシーが実行されます。同様に、駆動コンテキストがNULLである場合は、すべてのポリシー・グループのポリシーが規定されます。データにアクセスするアプリケーションは、セキュリティ設定モジュール(アプリケーション・コンテキストを設定するモジュール)を回避できないため、該当するすべてのポリシーが適用されます。

同一の表、ビューまたはシノニムに複数の駆動コンテキストを適用して、それぞれを個別に処理できます。これによって、複数のアクティブなポリシーを設定して規定できます。

たとえば、福利厚生アプリケーションと財務アプリケーションをホスティングするホスト企業があり、これらのアプリケーションが、いくつかのデータベース・オブジェクトを共有している場合を想定します。この2つのアプリケーションは、SYS_DEFAULTポリシー・グループのSUBSCRIBERポリシーを使用して、ホスティング用にストライプ化されます。データ・アクセスは、最初にサブスクライバIDごとにパーティション化され、次に、ユーザーが福利厚生アプリケーションと財務アプリケーションのどちらにアクセスしているか(駆動コンテキストによって決定される)によってパーティション化されます。ホスティング・サービスを使用するA社が、自社のデータ・アクセスにのみ関連したカスタム・ポリシーを適用するとします。この場合は、駆動コンテキスト(COMPANY A SPECIALなど)を追加して、追加の特殊ポリシー・グループの適用をA社のデータ・アクセスのみに限定できます。このポリシーはA社のみに関連しているため、SUBSCRIBERポリシーの下では適用できません。基本的なホスティング・ポリシーは、他のポリシーから分離した方がより効率的です。

11.3.7.3 SYS_DEFAULTポリシー・グループを使用したデフォルト・ポリシー・グループ

セキュリティ・ポリシーのグループ内で、1つのセキュリティ・ポリシーをデフォルトのセキュリティ・ポリシーになるよう指定できます。

これは、セキュリティ・ポリシーをアプリケーション別に分割して常に有効になるようにする場合に便利です。デフォルト・セキュリティ・ポリシーを使用すると、開発者はすべての条件下で基礎となるセキュリティを規定できます。一方、アプリケーションごとにセキュリティ・ポリシーを分割(セキュリティ・グループを使用)すると、デフォルト・セキュリティ・ポリシーにアプリケーション固有のセキュリティ・レイヤーを追加できます。デフォルト・セキュリティ・ポリシーを実装するには、このデフォルト・セキュリティ・ポリシーをSYS_DEFAULTポリシー・グループに追加します。

このグループ内に定義されている、特定の表、ビューまたはシノニムに対するポリシーは、駆動コンテキストが指定するポリシー・グループとともに実行されます。前述のとおり、駆動コンテキストは、有効なポリシー・グループを指定するアプリケーション・コンテキストです。SYS_DEFAULTポリシー・グループには、ポリシーが含まれる場合と含まれない場合があります。SYS_DEFAULTポリシー・グループは削除できません。このポリシー・グループを削除すると、Oracle Databaseでエラーが発生します。

SYS_DEFAULTポリシー・グループに、複数のオブジェクトに対応付けられているポリシーを追加する場合、各オブジェクトには個別にSYS_DEFAULTポリシー・グループが対応付けられます。たとえば、scottスキーマのemp表に1つのSYS_DEFAULTポリシー・グループがある場合、scottスキーマのdept表には別のSYS_DEFAULTポリシー・グループが対応付けられます。これは、次のようにツリー構造に編成されます。

SYS_DEFAULT
  - policy1 (scott/emp)
  - policy3 (scott/emp)
SYS_DEFAULT
  - policy2 (scott/dept)

同一の名前を持つ複数のポリシー・グループを作成できます。特定のポリシー・グループを選択すると、対応付けられているスキーマとオブジェクト名が、画面右側のプロパティ・シートに表示されます。

11.3.7.4 各表、ビューまたはシノニムに対する複数のポリシー

同一の表、ビューまたはシノニムに対して複数のポリシーを設定できます。

たとえば、受注用の基本アプリケーションがあり、社内の各部門にはそれぞれ独自のデータ・アクセス規則があるとします。基本アプリケーションのポリシー関数を作成しなおさなくても、部門固有のポリシー関数を表に追加できます。

表に適用されるすべてのポリシーは、AND構文で規定されます。そのため、CUSTOMERS表に3つのポリシーを適用している場合、各ポリシーが表に適用されます。データにアクセスするアプリケーションに応じて異なるポリシーが適用されるように、ポリシー・グループおよびアプリケーション・コンテキストを使用して、ファイングレイン・アクセス・コントロールの規定を分割できます。これによって、開発グループ間でポリシーを調整する必要がなくなり、アプリケーションの開発が容易になります。また、常に適用する(たとえば、ホスト環境でサブスクライバによりデータ分割を規定する)デフォルト・ポリシー・グループを保持することもできます。

11.3.7.5 データベースへの接続に使用されるアプリケーションの検証

駆動コンテキストを実装するパッケージは、データベースへの接続に使用されるアプリケーションを正しく検証する必要があります。

Oracle Databaseは、コール・スタックをチェックして、駆動コンテキストを実装するパッケージによるコンテキスト属性の設定を確認しますが、パッケージ内では不適切な検証が発生する可能性があります。たとえば、データベース・ユーザーまたはエンタープライズ・ユーザーがデータベースに認識されているアプリケーションの場合、ユーザーには、駆動コンテキストを設定するパッケージに対するEXECUTE権限が必要です。BENEFITSアプリケーションの方がHRアプリケーションよりもアクセスが自由であることを理解しているユーザーについて考えてみます。(正しいポリシー・グループを駆動コンテキスト内に設定する)setctxプロシージャでは、実際に接続しているアプリケーションを判断するための検証が実行されないこと。つまり、このプロシージャでは、(3層システムに対する)着信接続のIPアドレス、またはユーザー・セッションのproxy_user属性がチェックされないこと。

ユーザーは、アクセスがより自由なBENEFITSポリシー・グループにコンテキストを設定する引数を駆動コンテキスト・パッケージに渡してから、かわりにHRアプリケーションにアクセスできます。setctxではアプリケーションに対してそれ以上の検証を行わないため、このユーザーは限定的なHRセキュリティ・ポリシーをバイパスしてしまいます。

一方、Oracle Virtual Private Databaseによるプロキシ認証を実装すると、ユーザーのかわりにデータベースに接続する中間層(およびアプリケーション)の識別情報を確認できます。これによって、データ・アクセスを仲介するアプリケーションごとに正しいポリシーが適用されます。

たとえば、開発者は、プロキシ認証機能を使用して、データベースに接続しているアプリケーション(中間層)がHRAPPSERVERであることを確認できます。このように、駆動コンテキストを実装するパッケージでは、ユーザー・セッションのproxy_userHRAPPSERVERかどうかを検証できます。その場合、HRポリシー・グループを使用するよう駆動コンテキストを設定できます。proxy_userHRAPPSERVERでない場合は、アクセスを拒否できます。

このような場合に、次の問合せが実行されるとします。

SELECT * FROM apps.benefit;

Oracle Databaseは、デフォルト・ポリシー・グループ(SYS_DEFAULT)およびアクティブなネームスペースHRのポリシーを選択します。この問合せは、内部で次のようにリライトされます。

SELECT * FROM apps.benefit 
 WHERE company = SYS_CONTEXT('ID','MY_COMPANY') 
 AND SYS_CONTEXT('ID','TITLE') = 'MANAGER';

11.3.8 Oracle Virtual Private Databaseポリシー・タイプを使用したパフォーマンスの最適化

Oracle Virtual Private Database (VPD)の動的、静的または共有ポリシー・タイプを使用して、パフォーマンスを最適化できます。

11.3.8.1 Oracle Virtual Private Databaseポリシー・タイプについて

ポリシーのポリシー・タイプを指定すると、Oracle Virtual Private Databaseポリシーの実行パフォーマンスを最適化できます。

ポリシー・タイプを使用して、Oracle DatabaseがOracle Virtual Private Databaseポリシーの述語をキャッシュする方法を制御します。ポリシー関数を実行すると、システム・リソースを大量に消費する場合があるため、ポリシーに対してポリシー・タイプを設定することを検討してください。ポリシー関数の実行回数を最小限に抑えることで、データベースのパフォーマンスを最適化できます。

選択できるポリシー・タイプは、DYNAMICSTATICSHARED_STATICCONTEXT_SENSITIVEおよびSHARED_CONTEXT_SENSITIVEの5種類です。これらのポリシー・タイプによって、ポリシーの述語を変更する頻度を正確に指定できます。ポリシー・タイプを指定するには、DBMS_RLS.ADD POLICYプロシージャのpolicy_typeパラメータを設定します。

11.3.8.2 ポリシー関数の自動再実行のための動的ポリシー・タイプ

DYNAMICポリシー・タイプを指定すると、ユーザーが仮想プライベート・データベースで保護されたデータベース・オブジェクトにアクセスするたびに、ポリシー関数が実行されます。

DBMS_RLS.ADD_POLICYプロシージャにポリシー・タイプを指定しない場合、ポリシーはデフォルトで動的になります。ポリシーを動的に構成するには、DBMS_RLS.ADD_POLICYプロシージャのpolicy_typeパラメータをDYNAMICに設定します。

動的ポリシー・タイプでは、静的ポリシーや状況依存ポリシー・タイプの場合と異なり、データベースのパフォーマンスは最適化されません。ただし、ポリシーを静的または状況依存に設定する前に、その都度実行されるDYNAMICポリシー・タイプでテストすることをお薦めします。最初にポリシー関数をDYNAMICポリシーでテストすると、何もキャッシュされていないため、ポリシー関数が各問合せに与える影響を調べることができます。これにより、パフォーマンスを最適化するために静的ポリシーまたは状況依存ポリシーを使用可能にする前に、関数が正常に機能することを確認できます。

文の実行開始時間と終了時間を測定するには、DBMS_UTILITY.GET_TIME関数を使用します。例:

-- 1. Get the start time:
SELECT DBMS_UTILITY.GET_TIME FROM DUAL;

  GET_TIME
----------
   2312721

-- 2. Run the statement:
SELECT COUNT(*) FROM HR.EMPLOYEES;

  COUNT(*)
----------
       107

-- 3. Get the end time:
SELECT DBMS_UTILITY.GET_TIME FROM DUAL;

  GET_TIME
----------
   2314319
11.3.8.3 例: DBMS_RLS.ADD_POLICYを使用したDYNAMICポリシーの作成

DBMS_RLS.ADD_POLICYプロシージャで、動的なOracle Virtual Private Databaseポリシーを作成できます。

例11-5に、DYNAMICポリシー・タイプの作成方法を示します。

例11-5 DBMS_RLS.ADD_POLICYを使用したDYNAMICポリシーの作成

BEGIN
 DBMS_RLS.ADD_POLICY(
  object_schema   => 'hr',
  object_name     => 'employees',
  policy_name     => 'secure_update',
  policy_function => 'hide_fin',
  policy_type     => dbms_rls.DYNAMIC);
END;
/
11.3.8.4 ポリシー関数の問合せごとの再実行を回避するための静的ポリシー

静的ポリシー・タイプを指定すると、インスタンス内のすべてのユーザーに対して同じ述語が規定されます。

Oracle Databaseでは静的ポリシーの述語がSGAに格納されるため、ポリシー関数は問合せごとに再実行されません。その結果、パフォーマンスが向上します。

静的ポリシーを使用可能にするには、そのポリシーを複数のオブジェクト間で共有するかどうかに応じて、DBMS_RLS.ADD_POLICYプロシージャのpolicy_typeパラメータをSTATICまたはSHARED_STATICのいずれかに設定します。

述語が同じでも、同じカーソルを実行するたびに異なる行セットが生成される場合があります。これは、述語によるデータのフィルタ処理がSYS_CONTEXTSYSDATEなどの属性によって異なるためです。

たとえば、ポリシーをSTATICまたはSHARED_STATICポリシー・タイプとして使用可能にする場合を想定します。この場合は、ポリシーで保護されたデータベース・オブジェクトに対して実行されるすべての問合せに次の述語が追加されます。

WHERE dept = SYS_CONTEXT ('hr_app','deptno')

述語は、問合せごとに変わりませんが、SYS_CONTEXTのセッション属性に基づいて問合せに適用されます。前述の例の述語では、ポリシーで保護されたデータベース・オブジェクトを問い合せているユーザーの部門番号がSYS_CONTEXTdeptno属性と一致する行のみを戻します。

ノート:

共有の静的ポリシーを使用する場合は、ポリシーの述語に、列名など特定のデータベース・オブジェクト固有の属性が含まれていないことを確認してください。

11.3.8.5 例: DBMS_RLS.ADD_POLICYを使用した静的ポリシーの作成

DBMS_RLS.ADD_POLICYプロシージャで、静的なOracle Virtual Private Database (VPD)ポリシーを作成できます。

例11-6に、STATICポリシー・タイプの作成方法を示します。

例11-6 DBMS_RLS.ADD_POLICYを使用した静的ポリシーの作成

BEGIN
 DBMS_RLS.ADD_POLICY(
  object_schema   => 'hr',
  object_name     => 'employees',
  policy_name     => 'secure_update',
  policy_function => 'hide_fin',
  policy_type     => DBMS_RLS.STATIC);
END;
/
11.3.8.6 例: 複数オブジェクト間でポリシーを共有するための共有の静的ポリシー

複数オブジェクト間でポリシーを共有するために、DBMS_RLS.ADD_POLICYプロシージャで共有の静的Oracle Virtual Private Databaseポリシーを作成できます。

たとえば、使用する財務データを含むHRスキーマの2番目の表に例11-6のポリシーを適用する場合、両方の表でSHARED_STATIC設定を使用します。

例11-7に、同じポリシーを共有する2つの表に対してSHARED_STATICポリシー・タイプを設定する方法を示します。

例11-7 複数オブジェクト間でポリシーを共有するための共有の静的ポリシーの作成

-- 1. Create a policy for the first table, employees:
BEGIN
 DBMS_RLS.ADD_POLICY(
  object_schema   => 'hr',
  object_name     => 'employees',
  policy_name     => 'secure_update',
  policy_function => 'hide_fin',
  policy_type     => dbms_rls.SHARED_STATIC);
END;
/
-- 2. Create a policy for the second table, fin_data:
BEGIN
 DBMS_RLS.ADD_POLICY(
  object_schema   => 'hr',
  object_name     => 'fin_data',
  policy_name     => 'secure_update',
  policy_function => 'hide_fin',
  policy_type     => dbms_rls.SHARED_STATIC);
END;
/
11.3.8.7 静的ポリシーおよび共有の静的ポリシーを使用する場合

静的ポリシーは、すべての問合せに同じ述語が必要で、高いパフォーマンスが不可欠なホスト環境などに最適です。

このような環境では、ポリシー関数がすべての問合せに同じ述語を追加すると、ポリシー関数を再実行するたびに不要なオーバーヘッドがシステムに加わります。たとえば、競争相手である複数の顧客企業に関する市場調査データが含まれたデータ・ウェアハウスを考えてみます。このウェアハウスでは、各企業が自社の市場調査データのみを参照できるポリシーを規定する必要があり、このポリシーは次の述語で表現されます。

WHERE subscriber_id = SYS_CONTEXT('customer', 'cust_num')

アプリケーション・コンテキストに対してSYS_CONTEXTを使用すると、データベースでは、戻される行を動的に変更できます。関数を再実行する必要はなく、述語はSGAにキャッシュされるため、システム・リソースを節約でき、パフォーマンスが向上します。

11.3.8.8 変更されるアプリケーション・コンテキスト属性の状況依存ポリシー

状況依存ポリシーは、どの述語が問合せを実行しているかに応じて異なる述語を適用する必要がある場合に便利です。

たとえば、マネージャには述語WHERE groupmanagersに設定され、従業員には述語WHERE empno_ctxemp_idに設定される場合を考えてみます。状況依存ポリシーでは、マネージャのログイン時にマネージャが確認する必要がある情報のみ表示し、従業員のログイン時に従業員が確認する必要がある情報のみ表示できます。このポリシーは、アプリケーション・コンテキストを使用して、使用する述語を決定します。

静的ポリシーとは対照的に、状況依存ポリシーは必ずしも述語をキャッシュしません。状況依存ポリシーの場合、データベースでは、述語は文の解析後に変更されると想定しています。ただし、ローカル・アプリケーション・コンテキストに変更がない場合、Oracle Databaseはユーザー・セッション内でポリシー関数を再実行しません。ユーザー・セッション中にアプリケーション・コンテキストの属性の変更がある場合、デフォルトでは、データベースはポリシー関数を再実行して、初期解析からの述語へのすべての変更を取得していることを確認します。これにより、関連付けられている属性が変更されていない場合、ポリシー関数の再実行が必要なくなります。namespaceおよびattributeパラメータを含めて、特定のアプリケーション・コンテキストへの評価を制限できます。

ポリシーでnamespaceおよびattributeパラメータを使用する場合、次のガイドラインに従います。

  • 1つだけではなくnamespaceおよびattributeパラメータの両方を指定していることを確認します。

  • ポリシーにDBMS_RLS.CONTEXT_SENSITIVEまたはSHARED_CONTEXT_SENSITIVEに設定されているpolicy_type引数があることを確認します。静的または動的ポリシーのnamespaceおよびattributeパラメータを使用できません。

仮想プライベート・データベースのポリシー関数に関連付けられている属性がない場合、Oracle Databaseは、アプリケーション・コンテキストの変更の状況依存関数を評価します。

共有の状況依存ポリシーは、複数のデータベース・オブジェクト間で共有できる点を除いて、通常の状況依存ポリシーと同じように動作します。このポリシー・タイプの場合、すべてのオブジェクトがUGAのポリシー関数を共有でき、この場合、述語はローカル・セッション・コンテキストが変更されるまでキャッシュされます。

11.3.8.9 例: DBMS_RLS.ADD_POLICYを使用した状況依存ポリシーの作成

DBMS_RLS.ADD_POLICYプロシージャで、Oracle Virtual Private Database状況依存ポリシーを作成できます。

例11-8は、empno_ctxネームスペースおよびemp_id属性への変更のみにポリシーが評価されるCONTEXT_SENSITIVEポリシーの作成方法を示しています。

例11-8 DBMS_RLS.ADD_POLICYを使用した状況依存ポリシーの作成

BEGIN
 DBMS_RLS.ADD_POLICY(
  object_schema   => 'hr',
  object_name     => 'employees',
  policy_name     => 'secure_update',
  policy_function => 'hide_fin',
  policy_type     => dbms_rls.CONTEXT_SENSITIVE,
  namespace       => 'empno_ctx',
  attribute       => 'emp_id');
END;
/
11.3.8.10 例: VPD状況依存ポリシーのキャッシュされた文のリフレッシュ

DBMS_RLS.REFRESH_POLICY文で、Oracle Virtual Private Database状況依存ポリシーのキャッシュされた文をリフレッシュできます。

例11-9は、DBMS_RLS.REFRESH_POLICYプロシージャを実行して仮想プライベート・データベースの状況依存ポリシーに関連付けられているすべてのキャッシュされた文を手動でリフレッシュできることを示しています。

例11-9 VPD状況依存ポリシーのキャッシュされた文のリフレッシュ

BEGIN
 DBMS_RLS.REFRESH_POLICY(
  object_schema   => 'hr',
  object_name     => 'employees',
  policy_name     => 'secure_update');
END;
/
11.3.8.11 例: 既存の状況依存ポリシーの変更

DBMS_RLS.ALTER_POLICYプロシージャで、Oracle Virtual Private Databaseポリシーを変更できます。

例11-10は、関連するコンテキスト属性が変更される場合にのみorder_update_polポリシー関数を実行するためにDBMS_RLS.ALTER_POLICY文を使用して既存の状況依存ポリシーを変更する方法を示しています。

例11-10 既存の状況依存ポリシーの変更

BEGIN
 DBMS_RLS.ALTER_POLICY(
  object_schema   => 'oe',
  object_name     => 'orders',
  policy_name     => 'order_update_pol',
  alter_option    =>  DBMS_RLS.ADD_ATTRIBUTE_ASSOCIATION,
  namespace       => 'empno_ctx',
  attribute       => 'emp_role');
END;
/
11.3.8.12 例: 共有の状況依存ポリシーの使用による複数オブジェクト間でのポリシーの共有

複数オブジェクトがあるポリシーを共有するために、DBMS_RLS.ADD_POLICYプロシージャを使用して、共有の状況依存のOracle Virtual Private Databaseポリシーを作成できます。

例11-11は、複数の表でポリシーを共有する2つの共有の状況依存ポリシーを作成する方法およびempno_ctxネームスペースおよびemp_id属性への変更のみに評価を制限する方法を示しています。

例11-11 DBMS_RLS.ADD_POLICYを使用した共有の状況依存ポリシー

-- 1. Create a policy for the first table, employees:
BEGIN
 DBMS_RLS.ADD_POLICY(
  object_schema   => 'hr',
  object_name     => 'employees',
  policy_name     => 'secure_update',
  policy_function => 'hide_fin',
  policy_type     => dbms_rls.SHARED_CONTEXT_SENSITIVE,
  namespace       => 'empno_ctx',
  attribute       => 'emp_id');
END;
/
--2. Create a policy for the second table, fin_data:
BEGIN
 DBMS_RLS.ADD_POLICY(
  object_schema   => 'hr',
  object_name     => 'fin_data',
  policy_name     => 'secure_update',
  policy_function => 'hide_fin',
  policy_type     => dbms_rls.SHARED_CONTEXT_SENSITIVE,
  namespace       => 'empno_ctx',
  attribute       => 'emp_id');
END;
/

次のことに注意してください。

  • 共有の状況依存ポリシーを使用する場合は、ポリシーの述語に、列名など特定のデータベース・オブジェクト固有の属性が含まれていないことを確認してください。

  • 仮想プライベート・データベースの共有の状況依存ポリシーに関連付けられているすべてのキャッシュされた文を手動でリフレッシュするには、DBMS_RLS.REFRESH_GROUPED_POLICYプロシージャを実行します。

11.3.8.13 状況依存ポリシーおよび共有の状況依存ポリシーを使用する場合

状況依存ポリシーは、ユーザー・セッションごとに述語を変える必要はないが、ポリシーが異なるユーザーまたはグループに複数の異なる述語を規定する必要がある場合に使用します。

たとえば、単一のポリシーを持つsales_history表を考えてみます。このポリシーでは、アナリストは自分の製品のみを参照でき、地域担当者は自分の地域のみを参照できます。この場合、データベースは、ユーザーのタイプが変わるたびにポリシー関数を再実行する必要があります。サーバーによるポリシー関数の再実行なしに、ユーザーがログインして保護されたオブジェクトに対していくつかのDML文を発行できる場合は、パフォーマンスが向上します。

ノート:

複数のクライアントが1つのデータベース・セッションを共有するセッション・プーリングの場合は、クライアント切替え時に中間層でコンテキストを再設定する必要があります。

11.3.8.14 5種類のOracle Virtual Private Databaseポリシー・タイプの要約

Oracle Virtual Private Databaseには、ユーザーのニーズ(ホスト環境での使用など)に基づいて、5種類のポリシー・タイプが用意されています。

表11-2に、使用可能なポリシー・タイプの要約を示します。

表11-2 DBMS_RLS.ADD_POLICYのポリシー・タイプ

ポリシー・タイプ ポリシー関数の実行 使用例 複数オブジェクト間での共有

DYNAMIC

ポリシーで保護されたデータベース・オブジェクトがアクセスされるたびに、ポリシー関数を再実行します。

日中の特定時間は、ユーザーによるデータベース・オブジェクトへのアクセスを拒否する時間依存のポリシーなど、ポリシーの述語を問合せごとに生成する必要があるアプリケーション。

いいえ

STATIC

1回。それから述語はSGAにキャッシュされます脚注 1

ビューの置換

いいえ

SHARED_STATIC

STATICと同じ

同じ述語を複数のデータベース・オブジェクトに適用する必要があるデータ・ウェアハウスなどのホスト環境。

はい

CONTEXT_SENSITIVE

  • 文の解析時。

  • 文の実行時(カーソルが最後に使用された後にローカル・アプリケーション・コンテキストが変更された場合)。

ポリシーによって異なるユーザーまたはグループに複数の述語が規定される、3層セッション・プーリング・アプリケーション。

いいえ

SHARED_CONTEXT_SENSITIVE

データベース・セッションで最初にオブジェクトが参照されたとき。

述語はプライベート・セッション・メモリーであるUGAにキャッシュされるため、ポリシー関数を複数のオブジェクト間で共有できます。

CONTEXT_SENSITIVEと同じですが、複数のオブジェクトがセッションのUGAからポリシー関数を共有できます。

はい

脚注1

述語が同じでも、同じカーソルを実行するたびに異なる行セットが生成される場合があります。これは、述語によるデータのフィルタ処理がSYS_CONTEXTSYSDATEなどの属性によって異なるためです。

11.4 例: Oracle Virtual Private Databaseポリシーの作成

このチュートリアルでは、簡単なデータベース・セッション・ベースのOracle Virtual Privateポリシーの作成方法と、ポリシー・グループの作成方法を説明します。

11.4.1 例: 単純なOracle Virtual Private Databaseポリシーの作成

このチュートリアルでは、OEユーザー・アカウントを使用して単純なOracle Virtual Private Databaseポリシーを作成する方法を説明します。

11.4.1.1 このチュートリアルについて

このチュートリアルでは、アクセスを営業担当者159が作成したOE.ORDERS表内の受注に制限するVPDポリシーの作成方法を示します。

このポリシーは、基本的に次の文で表現されます。

SELECT * FROM OE.ORDERS;

この文を次のように変換します。

SELECT * FROM OE.ORDERS WHERE SALES_REP_ID = 159;

ノート:

マルチテナント環境を使用している場合、このチュートリアルは現在のPDBのみに適用されます。

11.4.1.2 ステップ1: OEユーザー・アカウントがアクティブであることの確認

まず、OEユーザー・アカウントが有効であることを確認する必要があります。

  1. SYSDBA管理権限を持つユーザーSYSとしてSQL*Plusにログインします。
    sqlplus sys as sysdba
    Enter password: password
    
  2. マルチテナント環境で、適切なPDBに接続します。

    例:

    CONNECT SYS@hrpdb AS SYSDBA
    Enter password: password
    

    使用可能なPDBを検索するには、show pdbsコマンドを実行します。現在のPDBを確認するには、show con_nameコマンドを実行します。

  3. OEのアカウント・ステータスを調べるには、DBA_USERSデータ・ディクショナリ・ビューを問い合せます。
    SELECT USERNAME, ACCOUNT_STATUS FROM DBA_USERS WHERE USERNAME = 'OE';
    

    ステータスはOPENである必要があります。DBA_USERSビューに、ユーザーOEがロックされて期限切れになっていると表示された場合は、次の文を入力して、OEアカウントのロックを解除し、新しいパスワードを作成します。

    ALTER USER OE ACCOUNT UNLOCK IDENTIFIED BY password;
    

    「パスワードの最低要件」のガイドラインに従って、passwordを安全なパスワードに置き換えます。セキュリティを向上させるため、以前のリリースのOracle Databaseで使用されたパスワードを再利用しないでください。

11.4.1.3 ステップ2: ポリシー関数の作成

次に、ポリシー関数を作成します。

ユーザーSYSとして、次の関数を作成します。この関数はWHERE SALES_REP_ID = 159句を、OE.ORDERS表の任意のSELECT文に追加します。(最初の行のCREATE OR REPLACEの前にカーソルを置くことで、このテキストをコピーして貼り付けることができます。)

CREATE OR REPLACE FUNCTION auth_orders( 
  schema_var IN VARCHAR2,
  table_var  IN VARCHAR2
 )
 RETURN VARCHAR2
 IS
  return_val VARCHAR2 (400);
 BEGIN
  return_val := 'SALES_REP_ID = 159';
  RETURN return_val;
 END auth_orders;
/

この例では、次のようになります。

  • schema_varおよびtable_varは、スキーマ名(OE)および表名(ORDERS)を格納するために指定する入力パラメータを作成します。最初に、スキーマ用のパラメータを定義し、次に、オブジェクト(この例では表)用のパラメータを定義します。パラメータは常にこの順序で作成します。作成する仮想プライベート・データベース・ポリシーでは、OE.ORDERS表を指定するためにこれらのパラメータが必要です。

  • RETURN VARCHAR2は、WHERE述語句に使用される文字列を返します。戻り値は常にVARCHAR2データ型になります。

  • IS ... RETURN return_valは、WHERE SALES_REP_ID = 159述語の作成が含まれます。

11.4.1.4 ステップ3: Oracle Virtual Private Databaseポリシーの作成

ポリシー関数の作成後、その関数をVPDポリシーに関連付けます。

  • DBMS_RLSパッケージのADD_POLICYプロシージャを使用して、次のポリシーを作成します。

    BEGIN
      DBMS_RLS.ADD_POLICY (
        object_schema    => 'oe',
        object_name      => 'orders',
        policy_name      => 'orders_policy',
        function_schema  => 'sys',
        policy_function  => 'auth_orders',
        statement_types  => 'select'
       );
     END;
    /

    この例では、次のようになります。

    • object_schema => 'oe'は、保護するスキーマ(この例ではOE)を指定します。

    • object_name => 'orders'は、保護するスキーマ内のオブジェクト(この例ではORDERS表)を指定します。

    • policy_name => 'orders_policy'は、このポリシーの名前をorders_policyと指定します。

    • function_schema => 'sys'は、auth_orders関数が作成されたスキーマを指定します。この例では、auth_ordersSYSスキーマに作成されています。ただし、通常は、セキュリティ管理者のスキーマに作成する必要があります。

    • policy_function => 'auth_orders'は、ポリシーを規定する関数を指定します。この例では、「ステップ2: ポリシー関数の作成」で作成したauth_orders関数を指定します。

    • statement_types => 'select'は、ポリシーを適用する操作を指定します。この例では、ユーザーが実行するすべてのSELECT文にポリシーが適用されます。

11.4.1.5 ステップ4: ポリシーのテスト

Oracle Virtual Private Databaseポリシーを作成した直後に、ポリシーは有効になります。

ユーザー(スキーマの所有者を含む)が次にOE.ORDERSに対してSELECT文を実行すると、営業担当者159の受注のみにアクセスできます。

  1. ユーザーOEとして接続します。
    CONNECT oe -- Or, CONNECT OE@hrpdb
    Enter password: password
    
  2. 次のSELECT文を入力します。
    SELECT COUNT(*) FROM ORDERS;
    

    次の出力が表示されます。

     COUNT(*)
    ---------
            7
    

    ポリシーはユーザーOEに対して有効です。ここに示すように、受注表の105行の内、7行のみが戻されます。

    ただし、管理権限を持つユーザーは、表のすべての行にアクセスできます。

  3. SYSDBA管理権限を持つユーザーSYSとして接続します。
    CONNECT SYS AS SYSDBA -- Or, CONNECT SYS@hrpdb AS SYSDBA
    Enter password: password
    
  4. 次のSELECT文を入力します。
    SELECT COUNT(*) FROM OE.ORDERS;
    

    次の出力が表示されます。

     COUNT(*)
    ---------
          105
11.4.1.6 ステップ5: このチュートリアルのコンポーネントの削除

このチュートリアルのコンポーネントが不要になった場合、それらを削除できます。

  1. ユーザーSYSで、次のように関数とポリシーを削除します。
    DROP FUNCTION auth_orders;
    EXEC DBMS_RLS.DROP_POLICY('OE','ORDERS','ORDERS_POLICY');
    
  2. OEアカウントをロックして期限切れにする必要がある場合は、次の文を入力します。
    ALTER USER OE ACCOUNT LOCK PASSWORD EXPIRE;

11.4.2 チュートリアル: セッション・ベースのアプリケーション・コンテキスト・ポリシーの実装

このチュートリアルでは、データベース・セッション・ベースのアプリケーション・コンテキストを使用するOracle Virtual Private Databaseポリシーの作成方法を示します。

11.4.2.1 このチュートリアルについて

この例では、データベース・セッション・ベースのアプリケーション・コンテキストを使用して、顧客が自分の注文のみを参照できるというポリシーを実装する方法を示しています。

マルチテナント環境を使用している場合、このチュートリアルは現在のPDBのみに適用されます。

このチュートリアルでは、次の層のセキュリティを作成します。

  1. ユーザーがログインするとき、データベース・セッション・ベースのアプリケーション・コンテキストによって顧客かどうかがチェックされます。顧客でないユーザーでもログインできますが、このユーザーはこの例で作成する注文表にアクセスできません。

  2. ユーザーが顧客の場合はログインできます。顧客がログインした後、Oracle Virtual Private Databaseポリシーによって、このユーザーは自分の注文のみを参照できるように制限されます。

  3. さらなる制限として、Oracle Virtual Private Databaseポリシーによって、ユーザーは注文を追加、変更、または削除できなくなります。

11.4.2.2 ステップ1: ユーザー・アカウントとサンプル表の作成

まず、ユーザー・アカウントとサンプル表を作成します。

  1. SQL*Plusを起動して、管理権限を持つユーザーとしてログインします。
    sqlplus sys as sysdba
    Enter password: password
    
  2. マルチテナント環境で、適切なPDBに接続します。

    例:

    CONNECT SYS@hrpdb AS SYSDBA
    Enter password: password
    

    利用可能なPDBを検索するには、DBA_PDBSデータ・ディクショナリ・ビューを問い合せます。現在のPDBを確認するには、show con_nameコマンドを実行します。

  3. Oracle Virtual Private Databaseポリシーを管理する、次の管理ユーザーを作成します。

    次のSQL文では、このユーザーを作成してから、この例を終了するのに必要な権限をユーザーに付与します。

    CREATE USER sysadmin_vpd IDENTIFIED BY password CONTAINER = CURRENT;
    GRANT CREATE SESSION, CREATE ANY CONTEXT, CREATE PROCEDURE, CREATE TRIGGER, ADMINISTER DATABASE TRIGGER TO sysadmin_vpd;
    GRANT EXECUTE ON DBMS_SESSION TO sysadmin_vpd;
    GRANT EXECUTE ON DBMS_RLS TO sysadmin_vpd;
    

    「パスワードの最低要件」のガイドラインに従って、passwordを安全なパスワードに置き換えます。

  4. 次のローカル・ユーザーを作成します。
    CREATE USER tbrooke IDENTIFIED BY password CONTAINER = CURRENT;
    CREATE USER owoods IDENTIFIED BY password CONTAINER = CURRENT;
    
    GRANT CREATE SESSION TO tbrooke, owoods;
    

    passwordを安全なパスワードに置き換えます。

  5. この例で使用するサンプル・ユーザーSCOTTのアカウント・ステータスをチェックします。
    SELECT USERNAME, ACCOUNT_STATUS FROM DBA_USERS WHERE USERNAME = 'SCOTT';
    

    ステータスはOPENである必要があります。DBA_USERSビューに、ユーザーSCOTTがロックされて期限切れになっていると表示された場合は、次の文を入力して、SCOTTアカウントのロックを解除し、新しいパスワードを作成します。

    ALTER USER SCOTT ACCOUNT UNLOCK IDENTIFIED BY password;
    

    「パスワードの最低要件」のガイドラインに従って、passwordを安全なパスワードに置き換えます。セキュリティを向上させるため、以前のリリースのOracle Databaseで使用されたパスワードを再利用しないでください。

  6. ユーザーSCOTTとして接続します。
    CONNECT SCOTT -- Or, CONNECT SCOTT@hrpdb
    Enter password: password
    
  7. customers表を作成および移入します。
    CREATE TABLE customers (
     cust_no    NUMBER(4), 
     cust_email VARCHAR2(20),
     cust_name  VARCHAR2(20));
    
    INSERT INTO customers VALUES (1234, 'TBROOKE', 'Thadeus Brooke');
    INSERT INTO customers VALUES (5678, 'OWOODS', 'Oberon Woods');
    

    ユーザーの電子メールIDを入力する際には、大文字で入力します。後でアプリケーション・コンテキストのPL/SQLパッケージを作成するときに、SYS_CONTEXTファンクションのSESSION_USERパラメータではユーザー名が大文字であると想定されます。大文字でないと、そのユーザー用のアプリケーション・コンテキストを設定できません。

  8. ユーザーsysadmin_vpdには、ユーザーSCOTTと同様にcustomers表のSELECT権限が必要になるため、この権限をsysadmin_vpdに付与します。
    GRANT READ ON customers TO sysadmin_vpd;
    
  9. orders_tab表を作成して値を入力します。
    CREATE TABLE orders_tab (
      cust_no  NUMBER(4),
      order_no NUMBER(4));
    
    INSERT INTO orders_tab VALUES (1234, 9876);
    INSERT INTO orders_tab VALUES (5678, 5432);
    INSERT INTO orders_tab VALUES (5678, 4592);
    
  10. ユーザーtbrookeowoodsorders_tab表を問い合せる必要があるため、これらのユーザーにREADオブジェクト権限を付与します。
    GRANT READ ON orders_tab TO tbrooke, owoods;
    

orders_tab受注表には、2名のサンプル顧客tbrookeowoodsの購買レコードがあります。この段階では、これらの顧客がこの表を参照すると、すべての受注を参照できます。

11.4.2.3 ステップ2: データベース・セッション・ベースのアプリケーション・コンテキストの作成

次に、データベース・セッション・ベースのアプリケーション・コンテキストを作成します。

  1. ユーザーsysadmin_vpdで接続します。
    CONNECT sysadmin_vpd -- Or, CONNECT sysadmin_vpd@hrpdb
    Enter password: password
    
  2. 次の文を入力します。
    CREATE OR REPLACE CONTEXT orders_ctx USING orders_ctx_pkg;
    

    この文は、orders_ctxアプリケーション・コンテキストを作成します。ユーザーsysadmin_vpdがこのコンテキストを作成してsysadmin_vpdスキーマに対応付けた場合でも、SYSスキーマがこのアプリケーション・コンテキストを所有することに注意してください。

11.4.2.4 ステップ3: アプリケーション・コンテキストを設定するPL/SQLパッケージの作成

アプリケーション・コンテキストの作成後、パッケージを作成してコンテキストを設定します。

  • ユーザーsysadmin_vpdとして、次のPL/SQLパッケージを作成します。このパッケージは、顧客tbrookeおよびowoodsがそれぞれのアカウントにログインすると、データベース・セッション・ベースのアプリケーション・コンテキストを設定します。

    CREATE OR REPLACE PACKAGE orders_ctx_pkg IS 
      PROCEDURE set_custnum;
     END;
    /
    CREATE OR REPLACE PACKAGE BODY orders_ctx_pkg IS
      PROCEDURE set_custnum
      AS
        custnum NUMBER;
      BEGIN
         SELECT cust_no INTO custnum FROM SCOTT.CUSTOMERS
            WHERE cust_email = SYS_CONTEXT('USERENV', 'SESSION_USER');
         DBMS_SESSION.SET_CONTEXT('orders_ctx', 'cust_no', custnum);
      EXCEPTION
       WHEN NO_DATA_FOUND THEN NULL;
      END set_custnum;
    END;
    /

    この例では、次のようになります。

    • custnum NUMBERは、顧客IDを保持するcustnum変数を作成します。

    • SELECT cust_no INTO custnumは、SELECT文を実行し、scott.customers表のcust_no列データに格納されている顧客IDをcustnum変数にコピーします。

    • WHERE cust_email = SYS_CONTEXT('USERENV', 'SESSION_USER')は、WHERE句を使用して、ログインしたユーザーのユーザー名と一致するすべての顧客IDを検索します。

    • DBMS_SESSION.SET_CONTEXT('orders_ctx', 'cust_no', custnum)は、cust_no属性を作成した後、custnum変数に格納されている値に設定することで、orders_ctxアプリケーション・コンテキストの値を設定します。

    • EXCEPTION ... WHENは、WHEN NO_DATA_FOUNDシステム例外を追加して、SELECT cust_no INTO custnum ...文のSELECT文によって発生した可能性のあるno data foundエラーを捕捉します。

要約すると、sysadmin_vpd.set_cust_numプロシージャは、セッション・ユーザーの顧客IDを選択してcustnum変数に格納することによって、ユーザーが登録済顧客かどうかを識別します。ユーザーが登録済顧客の場合、Oracle Databaseによってこのユーザーにアプリケーション・コンテキスト値が設定されます。「ステップ6: ユーザー・アクセスを自分の注文に制限するPL/SQLポリシー関数の作成」に示すように、ポリシー関数では、コンテキスト値を使用して、ユーザーがorders_tab表内のデータに対して持つアクセスを制御します。

11.4.2.5 ステップ4: アプリケーション・コンテキストのPL/SQLパッケージを実行するログイン・トリガーの作成

ログイン・トリガーがPL/SQLパッケージ・プロシージャを実行し、次回のユーザー・ログイン時にアプリケーション・コンテキストが設定されるようにします。

  • ユーザーsysadmin_vpdで、次のログイン・トリガーを作成します。

    CREATE TRIGGER set_custno_ctx_trig AFTER LOGON ON DATABASE
     BEGIN
      sysadmin_vpd.orders_ctx_pkg.set_custnum;
     END;
    /
11.4.2.6 ステップ5: ログオン・トリガーのテスト

ログイン・トリガーは、sysadmin_vpd.orders_ctx_pkg.set_custnumプロシージャの実行時に、そのユーザーのアプリケーション・コンテキストを設定します。

  1. ユーザーtbrookeとして接続します。
    CONNECT tbrooke -- For a CDB, connect to the PDB, e.g., @hrpdb 
    Enter password: password
    
  2. 次の問合せを実行します。
    SELECT SYS_CONTEXT('orders_ctx', 'cust_no') custnum FROM DUAL;
    

    次の出力が表示されます。

    EMP_ID
    -------------------------------------------------------------------
    1234
11.4.2.7 ステップ6: ユーザー・アクセスを自分の注文に制限するPL/SQLポリシー関数の作成

次のステップは、ユーザーの問合せの表示を制御するPL/SQL関数を作成します。

ログインしたユーザーがSELECT * FROM scott.orders_tab問合せを実行したときに、関数の出力がそのユーザーの発注に制限されるようにします。
  1. ユーザーsysadmin_vpdで接続します。
    CONNECT sysadmin_vpd -- Or, CONNECT sysadmin_vpd@hrpdb
    Enter password: password
    
  2. 次の関数を作成します。
    CREATE OR REPLACE FUNCTION get_user_orders(
      schema_p   IN VARCHAR2,
      table_p    IN VARCHAR2)
     RETURN VARCHAR2
     AS
      orders_pred VARCHAR2 (400);
     BEGIN
      orders_pred := 'cust_no = SYS_CONTEXT(''orders_ctx'', ''cust_no'')'; 
     RETURN orders_pred;
    END;
    /
    

この関数は、「表示される注文がログインしたユーザーに属する場合」に変換されるWHERE述語を作成して返します。それからこのWHERE述語を、このユーザーがscott.orders_tab表に対して実行するあらゆる問合せに追加します。問合せが追加されると、この関数をorders_tab表に適用するOracle Virtual Private Databaseポリシーを作成できます。

11.4.2.8 ステップ7: 新しいセキュリティ・ポリシーの作成

最後に、VPDセキュリティ・ポリシーを作成します。

  • ユーザーsysadmin_vpdとして、DBMS_RLS.ADD_POLICYプロシージャを使用して、ポリシーを次のように作成します。

    BEGIN
     DBMS_RLS.ADD_POLICY (
      object_schema    => 'scott', 
      object_name      => 'orders_tab', 
      policy_name      => 'orders_policy', 
      function_schema  => 'sysadmin_vpd',
      policy_function  => 'get_user_orders',
      statement_types  => 'select',
      policy_type      => DBMS_RLS.CONTEXT_SENSITIVE,
      namespace        => 'orders_ctx',
      attribute        => 'cust_no');
    END;
    /
    

この文は、SCOTTスキーマで、orders_policyという名前のポリシーを作成して、顧客が自分の注文について問い合せるためのorders_tab表に適用します。get_user_orders関数が実装するこのポリシーは、sysadmin_vpdスキーマに格納されます。このポリシーは、さらに、ユーザーがSELECT文のみを発行するように制限します。namespaceおよびattributeパラメータは、以前に作成したアプリケーション・コンテキストを指定します。

11.4.2.9 ステップ8: 新しいポリシーのテスト

これで、すべてのコンポーネントが作成されたため、ポリシーをテストします。

  1. ユーザーtbrookeとして接続します。
    CONNECT tbrooke -- Or, CONNECT tbrooke@hrpdb
    Enter password: password
    

    ユーザーtbrookeは、アプリケーション・コンテキストに定義した要件を通過できるため、ログインできます。

  2. ユーザーtbrookeで、購買レコードにアクセスします。
    SELECT * FROM scott.orders_tab;
    

    次の出力が表示されます。

       CUST_NO    ORDER_NO
    ----------  ----------
          1234        9876
    

    ユーザーtbrookeは、2番目のテストを通過します。このユーザーは、scott.orders_tab表にある自分の注文のみにアクセスできます。

  3. ユーザーowoodsとして接続し、購買レコードにアクセスします。
    CONNECT owoods -- For a CDB, connect to the PDB, e.g., @hrpdb
    Enter password: password
    
    SELECT * FROM scott.orders_tab
    

    次の出力が表示されます。

       CUST_NO    ORDER_NO
    ----------  ----------
          5678        5432
          5678        4592
    

    ユーザーtbrookeとユーザーowoodsはログインでき、自分の注文のリストを参照できます。

次のことに注意してください。

  • ユーザーの職位に基づいて複数の述語を作成できます。たとえば、営業担当者は自分の担当顧客のレコードのみを参照でき、受注入力担当はすべての顧客注文を参照できます。ユーザーの職位のコンテキスト値に基づいて別の述語を返すようにcustnum_sec機能を拡張できます。

  • ファイングレイン・アクセス・コントロール・パッケージ内でアプリケーション・コンテキストを使用することによって、実際には解析済の文の中にバインド変数が指定されます。例:

    SELECT * FROM scott.orders_tab 
    WHERE cust_no = SYS_CONTEXT('order_entry', 'cust_num');
    

    この文は完全に解析および最適化されますが、order_entryコンテキストに対するユーザーのcust_num属性値の評価は、実行時に行われます。これは、最適化された文には、その文を発行するユーザーごとに異なる形態で実行されるという利点があることを意味します。

    ノート:

    この例の関数のパフォーマンスは、cust_noに索引を作成するとさらに向上します。

  • コンテキスト属性は、データベース表(複数も可)のデータ、またはLightweight Directory Access Protocol(LDAP)を使用するディレクトリ・サーバーのデータに基づいて設定できます。

ノート:

トリガーの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

動的に生成された述語の中でアプリケーション・コンテキストを使用するこの例と、述語の中で副問合せを使用するOracle Virtual Private Databaseポリシーについてを比較してください。

11.4.2.10 ステップ9: このチュートリアルのコンポーネントの削除

このチュートリアルのコンポーネントが不要になった場合、それらを削除できます。

  1. ユーザーSCOTTとして接続します。
    CONNECT SCOTT -- Or, CONNECT SCOTT@hrpdb
    Enter password: password
    
  2. orders_tabおよびcustomers表を削除します。
    DROP TABLE orders_tab;
    DROP TABLE customers; 
    
  3. ユーザーSYSとしてAS SYSDBAで接続します。
    CONNECT SYS AS SYSDBA -- Or, CONNECT SYS@hrpdb AS SYSDBA
    Enter password: password
    
  4. 次の文を実行して、この例で使用したコンポーネントを削除します。
    DROP CONTEXT orders_ctx;
    DROP USER sysadmin_vpd CASCADE;
    DROP USER tbrooke;
    DROP USER owoods;

11.4.3 例: Oracle Virtual Private Databaseポリシー・グループの実装

このチュートリアルでは、Oracle Virtual Private Databaseポリシー・グループの作成方法を示します。

11.4.3.1 このチュートリアルについて

このチュートリアルでは、Oracle Virtual Private Database (VPD)を使用してポリシー・グループを作成する方法を示します。

アプリケーションで使用する一連のポリシーをグループ化する方法は、「Oracle Virtual Private Databaseのポリシー・グループ」を参照してください。非データベース・ユーザーがアプリケーションにログインすると、Oracle Databaseでは、適切なポリシー・グループ内で定義されたポリシーに基づいてユーザーにアクセス権が付与されます。

列レベルのアクセス制御の場合、各列または非表示の列セットが1つのポリシーで制御されます。この例では、2つの列セットを非表示にする必要があります。そのため、非表示にする列セットごとに1つずつ、2つのポリシーを作成する必要があります。ユーザーごとに必要なポリシーは1つのみのため、駆動アプリケーション・コンテキストによってポリシーが分割されます。

ノート:

マルチテナント環境を使用している場合、このチュートリアルは現在のPDBのみに適用されます。

11.4.3.2 ステップ1: この例で使用するユーザー・アカウントと他のコンポーネントの作成

まず、このチュートリアルのユーザー・アカウントと表を作成し、適切な権限を付与する必要があります。

  1. SYSDBA管理権限を持つユーザーSYSとしてログインします。
    sqlplus sys as sysdba
    Enter password: password
    
  2. マルチテナント環境で、適切なPDBに接続します。

    例:

    CONNECT SYS@hrpdb AS SYSDBA
    Enter password: password
    

    使用可能なPDBを検索するには、show pdbsコマンドを実行します。現在のPDBを確認するには、show con_nameコマンドを実行します。

  3. 次のローカル・ユーザーを作成します。
    CREATE USER apps_user IDENTIFIED BY password CONTAINER = CURRENT;
    GRANT CREATE SESSION TO apps_user;
    CREATE USER sysadmin_pg  IDENTIFIED BY password CONTAINER = CURRENT;
    GRANT CREATE SESSION, CREATE PROCEDURE, CREATE ANY CONTEXT TO sysadmin_pg;

    「パスワードの最低要件」のガイドラインに従って、passwordを安全なパスワードに置き換えます。

  4. ユーザーsysadmin_pgに次の権限を追加付与します。
    GRANT EXECUTE ON DBMS_RLS TO sysadmin_pg;
    
  5. ユーザーOEでログインします。
    CONNECT OE -- Or, CONNECT OE@hrpdb
    Enter password: password
    

    OEアカウントがロックされて期限切れになっている場合、SYSDBA管理権限を持つユーザーSYSとして再接続してから、次の文を入力してアカウントのロックを解除し、新しいパスワードを指定します。

    ALTER USER OE ACCOUNT UNLOCK IDENTIFIED BY password;
    

    passwordを安全なパスワードに置き換えます。セキュリティを向上させるため、以前のリリースのOracle Databaseで使用されたパスワードを再利用しないでください。

  6. product_code_names表を作成します。
    CREATE TABLE product_code_names(
    group_a     varchar2(32),
    year_a      varchar2(32),
    group_b     varchar2(32),
    year_b      varchar2(32));
    
  7. product_code_names表に値をいくつか挿入します。
    INSERT INTO product_code_names values('Biffo','2008','Beffo','2004');
    INSERT INTO product_code_names values('Hortensia','2008','Bunko','2008');
    INSERT INTO product_code_names values('Boppo','2006','Hortensia','2003');
    
    COMMIT;
    
  8. product_code_names表のSELECT権限をapps_userユーザーに付与します。
    GRANT SELECT ON product_code_names TO apps_user;
11.4.3.3 ステップ2: 2つのポリシー・グループの作成

次に、2人の非データベース・ユーザーprovider_aおよびprovider_bにそれぞれポリシー・グループを作成する必要があります。

  1. ユーザーsysadmin_pgで接続します。
    CONNECT sysadmin_pg -- Or, CONNECT sysadmin_pg@hrpdb
    Enter password: password
    
  2. ユーザーprovider_aにより使用されるprovider_a_groupポリシー・グループを作成します。
    BEGIN
     DBMS_RLS.CREATE_POLICY_GROUP(
     object_schema   => 'oe',
     object_name     => 'product_code_names',
     policy_group    => 'provider_a_group');
    END;
    /
    
  3. ユーザーprovider_bにより使用されるprovider_b_groupポリシー・グループを作成します。
    BEGIN
     DBMS_RLS.CREATE_POLICY_GROUP(
     object_schema   => 'oe',
     object_name     => 'product_code_names',
     policy_group    => 'provider_b_group');
    END;
    /
11.4.3.4 ステップ3: ポリシー・グループを制御するPL/SQLファンクションの作成

ポリシー・グループには、ユーザーのデータ・アクセスをアプリケーションでどのように制御するかを定義する関数が必要です。

このポリシー・グループに作成する関数はユーザーprovider_aprovider_bに適用されます。
  1. ユーザーprovider_aがアクセスするデータを制限するvpd_function_provider_a関数を作成します。
    CREATE OR REPLACE FUNCTION vpd_function_provider_a 
     (schema in varchar2, tab in varchar2) return varchar2 as 
      predicate  varchar2(8) default NULL;
      BEGIN
       IF LOWER(SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER')) = 'provider_a' 
        THEN predicate := '1=2';
       ELSE NULL;
      END IF;
      RETURN predicate;
    END;
    /
    

    この関数では、ログインするユーザーが確かにユーザーprovider_aであるかどうかがチェックされます。間違いない場合、provider_aが表示できるのは、product_code_names表の列group_aおよびyear_a内のデータのみとなります。列group_bおよびyear_b内のデータは、provider_aに表示されません。つまり、predicate := '1=2'を設定すると関連列が非表示になります。「ステップ5: PL/SQLファンクションのポリシー・グループへの追加」では、これらの列をSEC_RELEVANT_COLSパラメータに指定します。

  2. ユーザーprovider_aがアクセスするデータを制限するvpd_function_provider_b関数を作成します。
    CREATE OR REPLACE FUNCTION vpd_function_provider_b 
     (schema in varchar2, tab in varchar2) return varchar2 as 
      predicate  varchar2(8) default NULL;
      BEGIN
       IF LOWER(SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER')) = 'provider_b' 
        THEN predicate := '1=2';
       ELSE NULL;
      END IF;
      RETURN predicate;
    END;
    /
    

    vpd_function_provider_a関数と同様に、この関数では、ログインするユーザーが確かにユーザーprovider_bであるかどうかがチェックされます。間違いない場合、provider_bが表示できるのは、列group_bおよびyear_b内のデータのみであり、group_aおよびyear_a内のデータはprovider_bには表示されません。vpd_function_provider_a関数と同様に、predicate := '1=2'に指定すると、「ステップ5: PL/SQLファンクションのポリシー・グループへの追加」SEC_RELEVANT_COLSパラメータに指定する関連列が非表示になります。

11.4.3.5 ステップ4: 駆動アプリケーション・コンテキストの作成

アプリケーション・コンテキストにより、ログインする非データベース・ユーザーが使用する必要があるポリシーが決定されます。

  1. ユーザーsysadmin_pgで、次の駆動アプリケーション・コンテキストを作成します。
    CREATE OR REPLACE CONTEXT provider_ctx USING provider_package;
    
  2. アプリケーション・コンテキストに対してPL/SQL provider_packageパッケージを作成します。
    CREATE OR REPLACE PACKAGE provider_package IS
     PROCEDURE set_provider_context (policy_group varchar2 default NULL);
    END;
    /
    CREATE OR REPLACE PACKAGE BODY provider_package AS
     PROCEDURE set_provider_context (policy_group varchar2 default NULL) IS
     BEGIN
      CASE LOWER(SYS_CONTEXT('USERENV', 'CLIENT_IDENTIFIER'))
       WHEN 'provider_a' THEN
        DBMS_SESSION.SET_CONTEXT('provider_ctx','policy_group','PROVIDER_A_GROUP');
       WHEN 'provider_b' THEN
        DBMS_SESSION.SET_CONTEXT('provider_ctx','policy_group','PROVIDER_B_GROUP');
      END CASE;
     END set_provider_context;
    END;
    /
    
  3. provider_ctxアプリケーション・コンテキストをproduct_code_names表に関連付け、名前を指定します。
    BEGIN
     DBMS_RLS.ADD_POLICY_CONTEXT(
     object_schema  =>'oe',
     object_name    =>'product_code_names',
     namespace      =>'provider_ctx',
     attribute      =>'policy_group');
    END;
    /
    
  4. apps_userアカウントにprovider_packageパッケージに対するEXECUTE権限を付与します。
    GRANT EXECUTE ON provider_package TO apps_user;
11.4.3.6 ステップ5: PL/SQLファンクションのポリシー・グループへの追加

必要な関数を作成したら、適切なポリシー・グループに関数を関連付ける必要があります。

  1. vpd_function_provider_a関数をprovider_a_groupポリシー・グループに追加します。
    BEGIN 
     DBMS_RLS.ADD_GROUPED_POLICY(
     object_schema         => 'oe',
     object_name           => 'product_code_names',
     policy_group          => 'provider_a_group',
     policy_name           => 'filter_provider_a',
     function_schema       => 'sysadmin_pg',
     policy_function       => 'vpd_function_provider_a',
     statement_types       => 'select',
     policy_type           => DBMS_RLS.CONTEXT_SENSITIVE,
     sec_relevant_cols     => 'group_b,year_b',
     sec_relevant_cols_opt => DBMS_RLS.ALL_ROWS,
     namespace             => 'provider_ctx',
     attribute             => 'provider_group');
    END;
    /
    

    sec_relevant_colsパラメータで指定したgroup_bおよびyear_b列は、ユーザーprovider_aに対して非表示になります。

  2. vpd_function_provider_b関数をprovider_b_groupポリシー・グループに追加します。
    BEGIN 
     DBMS_RLS.ADD_GROUPED_POLICY(
     object_schema         => 'oe',
     object_name           => 'product_code_names',
     policy_group          => 'provider_b_group',
     policy_name           => 'filter_provider_b',
     function_schema       => 'sysadmin_pg',
     policy_function       => 'vpd_function_provider_b',
     statement_types       => 'select',
     policy_type           => DBMS_RLS.CONTEXT_SENSITIVE,
     sec_relevant_cols     => 'group_a,year_a',
     sec_relevant_cols_opt => DBMS_RLS.ALL_ROWS,
     namespace             => 'provider_ctx',
     attribute             => 'provider_group');
    END;
    /

    sec_relevant_colsパラメータで指定したgroup_aおよびyear_a列は、ユーザーprovider_bに対して非表示になります。

11.4.3.7 ステップ6: ポリシー・グループのテスト

これで、2つのポリシー・グループをテストできます。

  1. ユーザーapps_userとして接続した後、次の文を入力して、後で作成する出力の書式が適切に設定されるようにします。
    CONNECT apps_user -- Or, CONNECT apps_user@hrpdb
    Enter password: password
    
    col group_a format a16
    col group_b format a16;
    col year_a format a16;
    col year_b format a16;
    
  2. セッション識別子をprovider_aに設定します。
    EXEC DBMS_SESSION.SET_IDENTIFIER('provider_a');
    

    ここで、アプリケーションが識別子を設定します。識別子をprovider_aに設定すると、apps_userユーザーは、provider_a_groupポリシー・グループ内の製品に使用可能な製品のみが表示されるユーザーとして設定されます。

  3. provider_packageを実行し、コンテキストに基づいてポリシー・グループを設定します。
    EXEC sysadmin_pg.provider_package.set_provider_context;
    

    この時点で、アプリケーション・コンテキストが設定されたことを、次のように確認できます。

    SELECT SYS_CONTEXT('USERENV', 'CLIENT_IDENTIFIER') AS END_USER FROM DUAL;
    

    次の出力が表示されます。

    END_USER
    -----------------
    provider_a
    
  4. 次のSELECT文を入力します。
    SELECT * FROM oe.product_code_names;
    

    次の出力が表示されます。

    GROUP_A          YEAR_A           GROUP_B          YEAR_B
    ---------------- ---------------- ---------------- ----------------
    Biffo            2008
    Hortensia        2008
    Boppo            2006
    
  5. クライアント識別子をprovider_bに設定し、次の文を入力します。
    EXEC DBMS_SESSION.SET_IDENTIFIER('provider_b');
    EXEC sysadmin_pg.provider_package.set_provider_context;
    SELECT * FROM oe.product_code_names;
    

    次の出力が表示されます。

    GROUP_A          YEAR_A           GROUP_B          YEAR_B
    ---------------- ---------------- ---------------- ----------------
                                      Beffo            2004
                                      Bunko            2008
                                      Hortensia        2003
11.4.3.8 ステップ7: このチュートリアルのコンポーネントの削除

このチュートリアルのコンポーネントが不要になった場合、それらを削除できます。

  1. ユーザーOEとして接続します。
    CONNECT OE -- Or, CONNECT OE@hrpdb
    Enter password: password
    
  2. product_code_names表を削除します。
    DROP TABLE product_code_names;
    
  3. SYSDBA管理権限を持つユーザーSYSとして接続します。
    CONNECT SYS AS SYSDBA -- Or, CONNECT SYS@hrpdb AS SYSDBA
    Enter password: password
    
  4. このチュートリアルのアプリケーション・コンテキストとユーザーを削除します。
    DROP CONTEXT provider_ctx;
    DROP USER sysadmin_pg cascade;
    DROP USER apps_user;

11.5 他のOracle機能でのOracle Virtual Private Databaseの使用

Oracle Virtual Private DatabaseをOracleの他の機能と併用することの影響を理解しておく必要があります。

11.5.1 Oracle Virtual Private Databaseポリシーとエディション

エディションを扱う場合のOracle VPDの使用方法について理解しておく必要があります。

アプリケーションをエディションベースの再定義用に準備し、アプリケーションで使用される各表をエディショニング・ビューで保護する場合は、これらの表を保護するVirtual Private Databaseポリシーをエディショニング・ビューに移動する必要があります。

エディション付きオブジェクトにVirtual Private Databaseポリシーが付加されている場合、そのオブジェクトが表示されるすべてのエディションにそのポリシーが適用されます。エディション付きオブジェクトが実現化されると、そのオブジェクトに付加されているVPDポリシーが新しい実際のオブジェクトに新たに付加されます。継承されたエディション付きオブジェクトに新たにVPDポリシーを適用すると、そのオブジェクトが実現化されます。

関連項目:

エディションの詳細は、『Oracle Database開発ガイド』を参照してください。

11.5.2 VPD保護表に対するユーザーの問合せでのSELECT FOR UPDATE文

原則として、ユーザーは、Virtual Private Database保護表を問い合せる場合にFOR UPDATE句を含めないようにします。

Virtual Private Databaseテクノロジは、VPDポリシー関数によって生成されたVPD述語を含むインライン・ビューに対するユーザーの問合せをリライトする処理に基づいています。このため、ビューに対する制限事項はVPD保護表にも同様に適用されます。VPD保護表に対するユーザーの問合せでSELECT文にFOR UPDATE句が含まれていると、ほとんどの場合、その問合せは動作しません。ただし、VPDによって生成されたインライン・ビューが非常に単純である場合、ユーザーの問合せが動作することがあります。

関連項目:

SELECT文のFOR UPDATE句の制限事項の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

11.5.3 Oracle Virtual Private Databaseポリシーと外部結合またはANSI結合

Oracle Virtual Private Databaseでは、動的ビューを使用して、SQLをリライトします。

SQLに外部結合操作またはANSI操作が含まれていると、一部のビューがマージされない場合や、一部の索引が使用されない場合があります。この問題は既知の最適化制限です。この問題に対処するには、SQLをリライトして外部結合操作やANSI操作が使用されないようにします。

11.5.4 Oracle Virtual Private Databaseセキュリティ・ポリシーとアプリケーション

Oracle Virtual Private Databaseセキュリティ・ポリシーは、アプリケーション内ではなく、データベース内で適用されます。

したがって、ユーザーが異なるアプリケーションを使用してデータにアクセスしようとしても、Oracle Virtual Private Databaseセキュリティ・ポリシーを回避できません。データベースにセキュリティ・ポリシーを作成するもう1つの利点は、複数のアプリケーションで各セキュリティ・ポリシーを保持するのではなく、1箇所でセキュリティ・ポリシーを保持できることです。このため、Oracle Virtual Private Databaseは、アプリケーション・ベースのセキュリティよりも強力なセキュリティを提供し、所有権のコストもより低くなります。

データにアクセスしているアプリケーションに応じて、異なるセキュリティ・ポリシーを規定する必要がある場合があります。Order Entry(受注管理)およびInventory(在庫管理)の2つのアプリケーションが、両方ともorders表にアクセスする場合を考えてみます。Inventoryアプリケーションで、製品の種類に基づいてアクセスを制限するポリシーを使用するとします。同時に、Order Entryアプリケーションでも、顧客番号に基づいてアクセスを制限するポリシーを使用するとします。

この場合、アプリケーションによるファイングレイン・アクセスの使用を分割する必要があります。分割しないと、2つのポリシーが自動的に連結され、目的とする結果が得られません。複数のポリシー・グループ、および特定のトランザクションに対して有効なポリシー・グループを判断する駆動アプリケーションのコンテキストを指定できます。また、データ・アクセスに対して必ず適用するデフォルト・ポリシーも指定できます。たとえば、ホスティングされたアプリケーションでは、データ・アクセスはサブスクライバIDによって制限されます。

11.5.5 ファイングレイン・アクセス・コントロールのポリシー関数に対する自動再解析

各ポリシーに対して最新の述語が使用されるように、ファイングレイン・アクセス・コントロール対応のオブジェクトに対する問合せでポリシー関数が実行されます。

たとえば、問合せを午前8時から午後5時の間に限定する時間ベースのポリシー関数の場合は、正午にカーソルの実行を解析すると、その時点でこのポリシー関数が実行され、問合せに対してポリシーが再度参照されます。カーソルが午前9時に解析された場合でも、そのカーソルが後で(たとえば、正午に)実行されると、Virtual Private Databaseポリシー関数が再び実行され、カーソルの実行が現時点(正午)でも引き続き許可されるようになります。これにより、常に最新のセキュリティ・チェックが実行されます。

Virtual Private Databaseポリシー関数の自動再実行は、ポリシーを追加するときにDBMS_RLS.ADD_POLICY設定のSTATIC_POLICYTRUEに設定した場合は行われません。この設定の場合、ポリシー関数は同じ述語を戻します。

11.5.6 Oracle Virtual Private Databaseポリシーとフラッシュバック問合せ

データベース上での操作では、直前にコミットされた使用可能データが使用されます。

フラッシュバック問合せ機能により、過去のどこかの時点でのデータベースの問合せが可能になります。

フラッシュバック問合せを使用するアプリケーションを作成するには、SQL問合せでAS OF句を使用して、時間とシステム変更番号(SCN)のどちらかを指定して、指定された時間からコミット済データに対して問い合せます。DBMS_FLASHBACK PL/SQLパッケージを使用することもできます。このPL/SQLパッケージでは必要なコードが増えますが、複数の操作を実行でき、これらの操作のすべてが同じ時点を参照します。

ただし、Oracle Virtual Private Databaseポリシーで保護されているデータベース・オブジェクトに対してフラッシュバック問合せを使用すると、現行のポリシーが過去のデータに適用されます。現行のOracle Virtual Private Databaseポリシーをフラッシュバック問合せのデータに適用すると、最新のビジネス・ポリシーが反映されるため、安全性が高まります。

関連項目:

11.5.7 Oracle Virtual Private DatabaseとOracle Label Security

Oracle Virtual Private DatabaseとOracle Label Securityは併用できますが、その場合、セキュリティの例外に注意してください。

11.5.7.1 Oracle Virtual Private Databaseを使用したOracle Label Securityポリシーの規定

Oracle Virtual Private Databaseポリシーを使用して、Oracle Label Securityユーザー認可に基づいて列または行レベルのアクセス制御を提供できます。

一般に、次のステップを実行する必要があります。

  1. Oracle Label Securityのポリシーを作成したら、保護する必要がある表にこのポリシーを適用しないでください。(作成した仮想プライベート・データベース・ポリシーによって自動的に処理されます。)SA_SYSDBA.CREATE_POLICYプロシージャで、default_optionsパラメータをNO_CONTROLに設定します。

  2. Oracle Label Securityのラベル・コンポーネントを作成し、通常どおりユーザーを認可します。

  3. Oracle Virtual Private Databaseポリシーを作成する際には、次の操作を行います。

    • ポリシーについて作成するPL/SQLファンクションでは、Oracle Label SecurityのDOMINATESファンクションを使用して、ユーザーの認可をステップ2で作成したラベルと比較します。DOMINATESファンクションにより、ユーザーの認可が比較で使用されたラベルと等しい、またはラベルより機密性が高いかどうかが判別されます。ユーザー認可が通過した場合、ユーザーは列に対するアクセス権を付与されます。通過しない場合、ユーザーはアクセスを拒否されます。

    • 仮想プライベート・データベース・ポリシー定義で、保護する必要がある表にこのファンクションを適用します。DBMS_RLS.ADD_POLICYプロシージャで、機密性の高い列(SEC_RELEVANT_COLSパラメータ)および列のマスク(SEC_RELEVANT_COLS_OPTパラメータ)機能を使用して、Oracle Label Securityユーザー認可に基づいて列を表示または非表示にします。

関連項目:

支配ファンクションの詳細は、『Oracle Label Security管理者ガイド』を参照してください。
11.5.7.2 Oracle Virtual Private DatabaseおよびOracle Label Securityの例外

Oracle Virtual Private DatabaseおよびOracle Label Securityを使用する場合は、次の例外に注意してください。

これらのセキュリティ例外を次に示します。

  • データのエクスポート時、Oracle Virtual Private DatabaseおよびOracle Label Securityのポリシーはダイレクト・パス・エクスポート操作では規定されません。ダイレクト・パス・エクスポート操作では、Oracle Databaseはディスクからバッファ・キャッシュにデータを読み込み、行をエクスポート・クライアントに直接転送します。

  • Oracle Virtual Private DatabaseおよびOracle Label Securityのポリシーは、SYSスキーマのオブジェクトに適用できません。SYSユーザーおよびデータベースにDBA権限でアクセスするユーザー(CONNECT/AS SYSDBAなど)の場合、それらのユーザーのアクションにOracle Virtual Private DatabaseまたはOracle Label Securityのポリシーは適用されません。したがって、データベース・ユーザーSYSは、データベースからデータを抽出するために使用するエクスポート・モード、アプリケーションまたはユーティリティに関係なく、常にOracle Virtual Private DatabaseまたはOracle Label Securityの規定対象から除外されます。

    ただし、SYSDBAのアクションは、インストール時に監査を有効にし、監査証跡をオペレーティング・システムの保護位置に格納するように指定することによって監査できます。SYSユーザーはOracle Database Vaultを使用して詳細に監視できます。

  • EXEMPT ACCESS POLICY権限を直接的またはデータベース・ロールを介して付与されているデータベース・ユーザーは、Oracle Virtual Private Databaseの規定対象から除外されます。システム権限EXEMPT ACCESS POLICYを持つユーザーは、すべてのSELECTまたはDML操作(INSERTUPDATEおよびDELETE)において、ファイングレイン・アクセス・コントロール・ポリシーの対象から除外されます。これによって、インストールや、SYS以外のスキーマを介したデータベースのインポートとエクスポートなどの管理アクティビティが使いやすくなります。

    ただし、ポリシーを規定する次のオプションは、EXEMPT ACCESS POLICYが付与されている場合も規定されます。

    • INSERT_CONTROLUPDATE_CONTROLDELETE_CONTROLWRITE_CONTROLLABEL_UPDATEおよびLABEL_DEFAULT

    • Oracle Label SecurityのポリシーにALL_CONTROLオプションを指定した場合は、READ_CONTROLおよびCHECK_CONTROL以外のすべてが規定の対象として適用されます。

    EXEMPT ACCESS POLICYは、ファイングレイン・アクセス・コントロールを無効にするため、この権限は、ファイングレイン・アクセス・コントロールの規定を回避する正当な理由を持つユーザーに対してのみ付与する必要があります。この権限はWITH ADMIN OPTIONを使用して付与しないでください。これを使用すると、ユーザーが他のユーザーにEXEMPT ACCESS POLICY権限を譲渡して、ファイングレイン・アクセス・コントロールを回避する権限が伝播する可能性があります。

ノート:

  • EXEMPT ACCESS POLICY権限は、SELECTINSERTUPDATEおよびDELETEなどのオブジェクト権限の規定には影響しません。これらのオブジェクト権限は、ユーザーにEXEMPT ACCESS POLICY権限が付与されている場合も規定されます。

  • Oracle Virtual Private Databaseが使用するSYS_CONTEXT値は、フェイルオーバーのためのセカンダリ・データベースには伝播されません。

関連項目:

ダイレクト・パス・エクスポート操作の詳細は、『Oracle Databaseユーティリティ』を参照してください。

11.5.8 EXPDPユーティリティのaccess_methodパラメータを使用したデータのエクスポート

VPDポリシーが定義されているオブジェクトからデータをエクスポートする場合は注意してください。

access_methodパラメータがdirect_pathに設定されたOracle Data Pump Export (EXPDP)ユーティリティを使用して、データをスキーマからエクスポートしようとするとき、このスキーマに仮想プライベート・データベース・ポリシーが定義されているオブジェクトが含まれていると、ORA-31696エラー・メッセージが表示される場合があり、エクスポート操作は失敗します。

エラー・メッセージは次のとおりです。

ORA-31696: unable to export/import TABLE_DATA:"schema.table" using client specified DIRECT_PATH method

この問題は、スキーマ・レベルのエクスポートを、EXP_FULL_DATABASEロールを付与されていないユーザーとして実行する場合にのみ発生します。EXP_FULL_DATABASEロールを必要とするフル・データベース・エクスポート時には発生しません。EXP_FULL_DATABASEロールにはEXEMPT ACCESS POLICYシステム権限が含まれており、これにより仮想プライベート・データベース・ポリシーが無視されます。

潜在的な問題を見つけるには、EXPDP起動を再度試してください。ただし、access_methodパラメータをdirect_pathには設定しないでください。かわりに、automaticexternal_tableのどちらかを使用してください。潜在的な問題とは、たとえば次のような権限の問題です。

ORA-39181: Only partial table data may be exported due to fine grain access control on "schema_name"."object_name"

関連項目:

データ・ポンプ・エクスポートの使用に関する詳細は、『Oracle Databaseユーティリティ』を参照してください

11.5.9 ユーザー・モデルとOracle Virtual Private Database

Oracle Virtual Private Databaseは、複数のタイプのユーザー・モデルで使用できます。

これらのユーザー・モデルを次に示します。

  • アプリケーション・ユーザーがデータベース・ユーザーでもある場合。Oracle Databaseでは、ユーザーがデータベース・ユーザーか、データベースに認識されないアプリケーション・ユーザーかに関係なく、アプリケーションはユーザーごとにファイングレイン・アクセス・コントロールを規定できます。アプリケーション・ユーザーがデータベース・ユーザーでもある場合、Oracle Virtual Private Databaseは次のように規定されます。ユーザーがデータベースに接続すると、アプリケーションは各セッションに対するアプリケーション・コンテキストを設定します (様々な種類のユーザー・セッション・データを取得するための多くのパラメータを提供する、デフォルトのUSERENVアプリケーション・コンテキスト・ネームスペースを使用できます)。各セッションは異なるユーザー名で開始されるため、各ユーザーに対して異なるファイングレイン・アクセス・コントロール条件を規定できます。

  • OCIまたはJDBC/OCIを使用したプロキシ認証。プロキシ認証により、ユーザーごとに異なるファイングレイン・アクセス・コントロールが可能になります。これは、各セッション(OCIまたはJDBC/OCI)がそれぞれのアプリケーション・コンテキストを持つ個別のデータベース・セッションであるためです。

  • エンタープライズ・ユーザー・セキュリティと統合されたプロキシ認証。エンタープライズ・ユーザー・セキュリティを使用してプロキシ認証を統合した場合、Oracle Internet Directoryからユーザー・ロールおよび他の属性を取得してOracle Virtual Private Databaseポリシーを規定できます。(さらに、グローバルに初期化されたアプリケーション・コンテキストもこのディレクトリから取得できます。)

  • ユーザーがOne Big Application Userとして接続する場合。すべてのユーザーのかわりにシングル・ユーザーとしてデータベースに接続するアプリケーションでは、ユーザーごとのファイングレイン・アクセス・コントロールを規定できます。この1セッションのユーザーは、「One Big Application User」と呼ばれます。ただし、アプリケーション開発者は、そのセッションのコンテキスト内で、個別のアプリケーション・ユーザー(たとえば、REALUSER)を表すグローバル・アプリケーション・コンテキスト属性を作成できます。すべてのデータベース・セッションおよびすべての監査レコードはOne Big Application Userに対して作成されますが、各セッションはエンド・ユーザーに応じて異なる属性を保持できます。このモデルは、ユーザーの数が限定されていて、セッションが再利用されないアプリケーションに最適です。このモデルの場合、各セッションは同一のデータベース・ユーザーとして作成されるため、ロールやデータベース監査の範囲が限定されます。

  • Webベースのアプリケーション。Webベースのアプリケーションには、通常は何百人ものユーザーがいます。多数のユーザー要求に対するデータの取得をサポートするためにデータベースへの接続が持続的に行われる場合でも、このような接続は特定のWebベース・ユーザーに固有のものではありません。通常、Webベースのアプリケーションはスケーラビリティを提供するために、ユーザーごとに異なるセッションを保持するのではなく、接続を設定して再利用します。たとえば、WebユーザーJaneおよびAjitが中間層アプリケーションに接続すると、このアプリケーションは、2人のユーザーのかわりに、使用するデータベース・セッションを1つ確立します。通常、JaneもAjitもデータベースには認識されません。アプリケーションが接続するユーザー名を切り替えるため、どの時点でも、セッションを使用しているのはJaneまたはAjitのいずれかです。

    Oracle Virtual Private Databaseを使用すると、複数のグローバル・アプリケーション・コンテキストにアクセスする複数の接続が可能になり、接続プーリングが促進されます。この機能によって、個別ユーザー・セッションごとに別々のアプリケーション・コンテキストを確立する必要がなくなります。

表11-3に、Oracle Virtual Private Databaseをユーザー・モデルに適用する方法の要約を示します。

表11-3 様々なユーザー・モデルでのOracle Virtual Private Database

ユーザー・モデル 個別のデータベース接続 ユーザーごとの個別アプリケーション・コンテキスト 単一データベース接続 アプリケーションによるユーザー名の切替え

アプリケーション・ユーザーがデータベース・ユーザーでもある場合

はい

はい

いいえ

いいえ

OCIまたはJDBC/OCIを使用したプロキシ認証

はい

はい

いいえ

いいえ

エンタープライズ・ユーザー・セキュリティ脚注2と統合されたプロキシ認証

いいえ

いいえ

はい

はい

One Big Application User

いいえ

いいえ脚注3

いいえ

はい2

Webベースのアプリケーション

いいえ

いいえ

はい

はい

脚注2

ユーザー・ロールとその他の属性(グローバルに初期化されたアプリケーション・コンテキストも含む)は、Oracle Internet Directoryから取得してOracle Virtual Private Databaseを規定できます。

脚注3

アプリケーション開発者は、個別アプリケーション・ユーザー(たとえば、REALUSER)を表すグローバル・アプリケーション・コンテキスト属性を作成できます。その後、この属性を使用して、各セッション属性を制御したり、監査することができます。

11.6 Oracle Virtual Private Databaseのデータ・ディクショナリ・ビュー

Oracle Databaseには、Oracle Virtual Private Databaseポリシーに関する情報を表示するデータ・ディクショナリ・ビューが用意されています。

表11-4に、仮想プライベート・データベース固有のビューを示します

表11-4 VPDポリシーに関する情報を表示するデータ・ディクショナリ・ビュー

ビュー 説明

ALL_POLICIES

現行ユーザーがアクセス可能なオブジェクトに対するすべてのOracle Virtual Private Databaseセキュリティ・ポリシーが表示されます。

ALL_POLICY_ATTRIBUTES

ログインしたユーザーがVPDポリシーの所有者であるか、VPDポリシーがPUBLICに属する場合のすべてのアプリケーション・コンテキスト・ネームスペース、属性および仮想プライベート・データベース・ポリシーの関連付けが表示されます。

ALL_POLICY_CONTEXTS

現行ユーザーがアクセス可能なシノニム、表およびビューに定義されている駆動コンテキストが表示されます。駆動コンテキストは、Oracle Virtual Private Databaseポリシーで使用されるアプリケーション・コンテキストです。

ALL_POLICY_GROUPS

現行ユーザーがアクセス可能なシノニム、表およびビューに定義されているOracle Virtual Private Databaseポリシー・グループが表示されます。

ALL_SEC_RELEVANT_COLS

現行ユーザーがアクセス可能な表とビューに対するセキュリティ・ポリシーのセキュリティ関連列が表示されます。

DBA_POLICIES

データベース内のすべてのOracle Virtual Private Databaseセキュリティ・ポリシーが表示されます。

DBA_POLICY_ATTRIBUTES

状況依存および共有の状況依存仮想プライベート・データベース・ポリシーのすべてのアプリケーション・コンテキスト・ネームスペース、属性および仮想プライベート・データベース・ポリシーの関連付けが表示されます。

DBA_POLICY_GROUPS

データベース内のすべてのポリシー・グループが表示されます。

DBA_POLICY_CONTEXTS

データベース内のすべての駆動コンテキストが表示されます。このビューの列は、ALL_POLICY_CONTEXTSの各列と同じです。

DBA_SEC_RELEVANT_COLS

データベース内のすべてのセキュリティ・ポリシーのセキュリティ関連列が表示されます。

UNIFIED_AUDIT_TRAIL

統合監査およびファイングレイン監査のために、RLS_INFO列にVPD述語を取得します。

USER_POLICIES

現行ユーザーが所有するオブジェクトに対応付けられたすべてのOracle Virtual Private Databaseセキュリティ・ポリシーが表示されます。このビューにはOBJECT_OWNER列が表示されません。

USER_POLICY_ATTRIBUTES

仮想プライベート・データベース・ポリシーの所有者が現在のユーザーである場合のすべてのアプリケーション・コンテキスト・ネームスペース、属性および仮想プライベート・データベース・ポリシーの関連付けが表示されます。

USER_POLICY_CONTEXTS

現行ユーザーが所有するシノニム、表およびビューに定義されている駆動コンテキストが表示されます。このビューの列は、OBJECT_OWNER列以外はALL_POLICY_CONTEXTSの各列と同じです。

USER_SEC_RELEVANT_COLS

現行ユーザーが所有している表とビューに対するセキュリティ・ポリシーのセキュリティ関連列が表示されます。このビューの列は、OBJECT_OWNER列以外はALL_SEC_RELEVANT_COLSの各列と同じです。

USER_POLICY_GROUPS

現行ユーザーが所有するシノニム、表およびビューに定義されているポリシー・グループが表示されます。このビューにはOBJECT_OWNER列が表示されません。

V$VPD_POLICY

現在のPDBの場合、現在ライブラリ・キャッシュにキャッシュされているカーソルに対応付けられた、すべてのファイングレイン・セキュリティ・ポリシーと述語が表示されます。このビューは、SQL文に適用されたポリシーを検索するのに便利です。

ヒント:

仮想プライベート・データベース・ポリシーを使用するアプリケーションでエラーが見つかった場合は、これらのビューに加え、データベース・トレース・ファイルも確認してください。USER_DUMP_DEST初期化パラメータは、トレース・ファイルの現在の位置を示します。このパラメータの値は、SQL*PlusでSHOW PARAMETER USER_DUMP_DESTを発行して確認できます。

関連項目: