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

最近のアプリケーションは利用者は直接データベースに接続するのではなく、利用者はアプリケーションサーバーに接続し、アプリケーションサーバーがデータベースに接続することがほとんどです。いわゆる3層アーキテクチャというやつです。
この場合、データベースへはアプリケーションサーバーが接続します。アプリケーション用のひとつの代表アカウントでデータベースに接続してコネクションプールを作成し、すべての利用者はこのコネクションプールを共用します。
データベースからはすべての利用者が同じデータベースユーザーによる接続として見えるため、データベースはその問い合わせを要求したのが実際にどの利用者かを識別できません。
そのため、データベース側で利用者ごとのアクセス制御をおこなうことや、アクセス監査をとった時に実際にどの利用者がそのアクセスをおこなったかの識別をおこなうことが難しくなっています。

Oracle Databaseでは、アプリケーションからデータベースに実際の利用者の情報を伝達する手段として、クライアント識別子(Client Identifier)を提供しています。アプリケーションで現在の利用者名を設定すると、データベースではSYS_CONTEXT関数を利用して以下のように取得できます。

SQL> select sys_context('userenv','client_identifier') from dual;
SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER')
--------------------------------------------------------------------------------
tofukuda

 実際の利用者が誰だか分かることで、仮想プライベートデータベース(VPD: Virtual Private Database)やData Redaction機能で利用者ごとのアクセス制御をデータベース側に実装することができます。また、CLIENT_IDENTIFIERの値は、標準監査の監査証跡を確認するためのDBA_AUDIT_TRAILビューのCLIENT_ID列、12cからの統合監査の監査証跡を確認するためのUNIFIED_AUDIT_TRAILビューのCLIENT_IDENTIFIER列に格納されますので、データベースのアクセス監査証跡だけで実際にどの利用者がデータにアクセスしたかを確認することもできるようになります。

クライアント識別子は非常に便利な機能ですが、アプリケーション側で現在の利用者が誰かをデータベースに伝播するためのロジックを組み込む必要があります。

たとえば、PL/SQLの場合、DBMS_SESSIONパッケージのSET_IDENTIFIERプロシージャを利用します。

SQL> exec dbms_session.set_identifier('tofukuda');
PL/SQLプロシージャが正常に完了しました。

また、Javaアプリケーションでは、利用するJDBCのバージョンによって設定方法が異なります。

JDBC 11gの場合

String metrics[] = 
  new String[OracleConnection.END_TO_END_STATE_INDEX_MAX];
metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = "tofukuda";
conn.setEndToEndMetrics(metrics, (short) 0);

JDBC 12cの場合

conn.setClientInfo("E2E_CONTEXT.CLIENT_IDENTIFIER", "tofukuda");

コネクションプールを利用しているアプリケーションでは、コネクションプールを取得する際にクライアント識別子を設定する事になります。実際のアプリケーションの処理の流れはたとえば以下のようになります。

  1. アプリケーション開始
  2. 前処理
  3. コネクションプール取得
  4. クライアント識別子の設定
     
  5. データベース処理実行(SQL実行)
     
  6. クライアント識別子の値の削除(オプション)
  7. コネクションプール開放
  8. 後処理
  9. アプリケーション終了

アプリケーションへの変更はコネクションプールを取得する前にクライアント識別子を設定し、オプションでコネクションプールを開放する前に設定した値を消去します。フレームワークを利用している場合は、フレームワーク内にこのロジックを組み込むことで、アプリケーションの変更箇所を最小化できます。

WebLogic Serverを利用している場合には、設定だけでこの機能を利用することができます。
WebLogic Server 12cでは、データソース設定で「構成」タブの「アイデンティティ」タブで「接続時にクライアントIDを設定」と「データベース資格証明の使用」にチェックをつけてください。

 

 

 

また、データベースのバージョンが12cの場合には、アプリケーション側のweblogic.xmlに以下の権限設定を追加してください。

クラス名: oracle.jdbc.OracleSQLPermission
ターゲット: clientInfo.OCSID.CLIENTID
アクション: (空欄)

 

 

weblogic.xmlへの記載内容

<security-permission>
  <security-permission-spec>
    grant { permission oracle.jdbc.OracleSQLPermission "clientInfo.OCSID.CLIENTID", "" };
  </security-permission-spec>
</security-permission>

なお、WebLogic Server 10.3を利用している場合やその他の注意点は、以下の2014/5/27に実施した「WebLogic Server勉強会」のスライドもあわせて参考にしてください。

機能の詳細に関しては、以下のblogやその関連記事も併せて参考にしてください。

 

 

 

Webブラウザのみを利用してWebアプリケーションを開発可能なApplication Express (APEX)を利用している場合も、APEXアプリケーションにログインする際のユーザー名とセッションIDがカンマ区切りテキストの形でセッション識別子に設定されます。

APEXアプリケーションでのクライアント識別子の値の例

PUKU:2644558331440

データベースが実際の利用者を知ることができると、アクセス制御や監査の精度があがります。
クライアント識別子は便利な機能なのでぜひご利用ください。

「もくじ」にもどる