※ 本記事は2017年3月9日に公開されたものです。

前回はデータベースユーザーごとに同じ表への全件検索でも同じ結果を戻す仮想プライベートデータベースの設定方法を説明しました。しかし、現実のアプリケーションではアクセス制御のルールはこうも簡単ではありません。たとえば前回の設定ではアプリケーションのデータをメンテナンスしようとしても、すべてのデータを見れる人がいない状態です。 

アクセス制御のルールを作成するうえで重要なことは、どのようなルールなのかを明確に定義することです。必要最小限のデータしか見れないようにするというのは大前提ですが、必要最小限ではあいまいすぎます。どのような場合にどのデータにアクセスさせるか仮想プライベートデータベースではポリシーファンクションとして実装する必要がありますので、プログラムを前提として仕様を決める必要があります。この点を抑えていないと、アクセス制御の抜け道ができたり、新しいアクセス制御のルールの追加時にどのようにポリシーファンクションを変更すればよいのかが分からなくなってしまいます。

では実際にアクセス制御のルールを考えていきましょう。
まず、メンテナンス用のユーザーを考えます。メンテナンス用のユーザーは全件にアクセスできます。ただしいつでもどこからでもどのプログラムを利用してもデータにアクセスできてしまうのは危険なので、たとえば特定の端末から特定のプログラムを利用した場合のみアクセス可能とします。
それ以外の一般ユーザーは引き続き自分のデータにしかアクセスできないことにします。

フローにすると下記の通りです。

 

あとはフローにしたがってコーディングするだけです。

create or replace function app1.vpdfunc
  (v_schema varchar2, v_objname varchar2)
  return varchar2
is begin
  if upper(sys_context('userenv','session_user')) = 'PUKU' then
    if sys_context('userenv','ip_address') = '10.185.155.180' and
       sys_context('userenv','client_program_name') like 'sqlplus%' then
      return '1=1';
    else
      return '0=1';
    end if;
  else
    return 'name = upper(sys_context(''userenv'',''session_user''))';
  end if;
end;
/

ユーザー名、IPアドレス、プログラム名等を調べるときは事前に以下のSQLを発行したり、V$SESSIONビューを確認したりしてください。

select sys_context('userenv','session_user'),
       sys_context('userenv','ip_address'),
       sys_context('userenv','client_program_name')
  from dual;
実行例
SQL> select sys_context('userenv','session_user'),
  2         sys_context('userenv','ip_address'),
  3         sys_context('userenv','client_program_name')
  4    from dual;
SYS_CONTEXT('USERENV','SESSION_USER')
--------------------------------------------------------------------------------
SYS_CONTEXT('USERENV','IP_ADDRESS')
--------------------------------------------------------------------------------
SYS_CONTEXT('USERENV','CLIENT_PROGRAM_NAME')
--------------------------------------------------------------------------------
PUKU
10.185.155.180
sqlplus@catvari.jp.oracle.com (TNS V1-V3)

ファイングレインアクセスコントロールのポリシーを作成し、結果を確認してみましょう。

ポリシーの作成
begin
  dbms_rls.add_policy(
    object_schema => 'app1',
    object_name => 'testtab',
    policy_name => 'sample_vpdpol',
    function_schema => 'app1',
    policy_function => 'vpdfunc');
end;
/

SYSTEMからは見えるデータはありません。

SQL> show user
ユーザーは"SYSTEM"です。
SQL> select * from app1.testtab;
レコードが選択されませんでした。

SATOとITOは自分のデータのみ参照できます。

SQL> connect sato@appdb
パスワードを入力してください:
接続されました。
SQL> select * from app1.testtab;
NAME
----------------
SATO
SQL> connect ito/hoge@appdb
接続されました。
SQL> select * from app1.testtab;
NAME
----------------
ITO

メンテナンスユーザー(PUKU)は特定の端末の特定のアプリからはアクセス可能ですが、それ以外からはアクセスできません。

管理用端末からアクセス
SQL> select sys_context('userenv','session_user'),
  2         sys_context('userenv','ip_address'),
  3         sys_context('userenv','client_program_name')
  4    from dual;
SYS_CONTEXT('USERENV','SESSION_USER')
--------------------------------------------------------------------------------
SYS_CONTEXT('USERENV','IP_ADDRESS')
--------------------------------------------------------------------------------
SYS_CONTEXT('USERENV','CLIENT_PROGRAM_NAME')
--------------------------------------------------------------------------------
PUKU
10.185.155.180
sqlplus@catvari.jp.oracle.com (TNS V1-V3)
SQL> select * from app1.testtab;
NAME
----------------
SATO
ITO
それ以外の端末からアクセス
SQL> select sys_context('userenv','session_user'),
  2         sys_context('userenv','ip_address'),
  3         sys_context('userenv','client_program_name')
  4    from dual;
SYS_CONTEXT('USERENV','SESSION_USER')
--------------------------------------------------------------------------------
SYS_CONTEXT('USERENV','IP_ADDRESS')
--------------------------------------------------------------------------------
SYS_CONTEXT('USERENV','CLIENT_PROGRAM_NAME')
--------------------------------------------------------------------------------
PUKU
10.185.155.204
sqlplus@dbsec.jp.oracle.com (TNS V1-V3)
SQL> select * from app1.testtab;
レコードが選択されませんでした。 

なお、ポリシーファンクションで戻り値が条件句の形式をとっていないなどのエラーが発生した場合には、SQL文実行時に下記のエラーが戻ります。ポリシーファンクションを修正して下さい。

SQL> select * from app1.testtab;
select * from app1.testtab
                   *
行1でエラーが発生しました。:
ORA-28113: ポリシー述語にエラーがあります。  

今回は仮想プライベートデータベースで管理者は全件アクセスできるというポリシーを実現するためのポリシーファンクションを作成しました。しかし、今回まではデータベースユーザーごとのアクセス制御をおこなっています。次回はコネクションプールを利用したアプリケーションユーザーごとにアクセス制御をおこなう方法を紹介します。

「もくじ」にもどる