プライマリ・コンテンツに移動
Oracle® Audit Vault and Database Firewall開発者ガイド
リリース12.2.0
E70387-11
目次へ移動
目次
索引へ移動
索引

前
次

4 Javaベースの監査証跡収集プラグイン

Oracle Audit Vault and Database FirewallにはJavaベースの監査証跡収集プラグインのセットが用意されており、これを使用してカスタム・プラグインを作成することができます。

4.1 Javaベースの収集プラグインについて

テンプレートベースの収集プラグインで監査証跡データを簡単に処理できない場合は、Javaベースの収集プラグインを使用できます

カスタム収集プラグインの作成にJava APIを使用すると、収集プラグインをより柔軟に設計できます。

一般的には、次のような必要がある場合にJavaタイプの収集プラグインを使用します。

  • データベース表またはXMLファイルに書き込まれていない証跡を読み取る。

  • 表またはXMLファイルに書き込まれた複雑な証跡を読み取る。

4.2 Javaベースの収集プラグインを使用するためのJDKの要件

Javaベースの収集プラグインには、コードをコンパイルおよびテストするためのJDKが必要です。出荷後、収集プラグインはエージェントと同じJVMで実行されるため、エージェントの開始に使用したのと同じJDKを使用することをお薦めします。JDKでクラスをコンパイルするには、javacコンパイラの-targetオプションを同じバージョンに設定します。詳細は、JDKのドキュメントを参照してください。

4.3 Javaベースの収集プラグイン内の制御のフロー

収集プラグインは、監査証跡にアクセスして監査証跡から監査レコードおよび関連フィールドを抽出した後、その監査レコードをAudit Vaultイベントにマップし、すべてのフィールドをAudit Vaultフィールドにマップします。次に、収集プラグインは、Audit Vaultイベントとフィールドを収集フレームワークに渡し、これがAudit Vault Serverに情報を送信します。

監査証跡収集の制御プロセスのフローは、次のとおりです。

  1. Audit Vault Serverは、エージェント・フレームワークに指示して、特定の監査証跡から収集するためのスレッドを作成します。
  2. エージェントで作成された新しいスレッドは、特定の監査証跡を収集します。

    この時点で、制御は収集フレームワークに渡されます。

  3. スレッド内で、収集フレームワークはAudit Vault Serverに接続し、収集する監査証跡の構成情報を問い合せます。

    また、その証跡に設定された最後のチェックポイントの情報をリクエストします。

  4. 現在の情報を使用して、収集フレームワークは、プラグイン・マニフェスト・ファイルを通じて、正しい収集プラグイン内で起動する正しいJavaクラスを判断します。構成情報をこのクラスに渡して、自身の初期化を要求します。
  5. 収集プラグインが自身を初期化したら、収集フレームワークは繰り返しループします。各ループ内で、収集フレームワークは次の処理を実行します。
    • 収集プラグインに監査証跡の追加の監査レコードを要求します。

      収集プラグインは、追加の監査レコードをAudit Vaultが予期する監査レコードの形式に変換(マップ)し、収集APIを通じて収集フレームワークに渡します。

  6. 収集プラグインは定期的に、チェックポイントおよびメトリック情報を収集フレームワークに送信します。収集プラグインによる制御中に、収集プラグインは同じフローでこれを行います(例: 収集フレームワークによるhasNext()を呼出し時)。
  7. Audit Vault Serverがコマンドを収集フレームワークに送信すると、収集フレームワークはそれを動作する収集プラグインに渡します。

    収集フレームワークがAudit Vault ServerからSTOPコマンドを受け取ると、収集プラグインにレコードの送信を停止するよう通知します。次に、収集スレッドを終了し、自身を停止します。

    収集フレームワークがAudit Vault ServerからRECONFIGUREコマンドを受け取ると、収集プラグインにsetAttribute()を使用して属性を設定するよう通知します。

4.4 収集フレームワークの便利なクラスおよびインタフェース

独自の収集に特に便利な、Oracle Audit Vault Javaベースの収集プラグインのクラスおよびインタフェースについて学習します

次の画像はAuditService、CollectorContextおよびClass AVLoggerのクラスとインタフェース間の関係を示しています。

図4-1 AuditService、CollectorContextおよびClass AVLoggerのクラスとインタフェース

図4-1の説明が続きます
「図4-1 AuditService、CollectorContextおよびClass AVLoggerのクラスとインタフェース」の説明

次の図に、Javaベースの収集プラグインを記述する際に必要となる、収集フレームワークの様々なクラスおよびインタフェースを示します。

図4-2 収集プラグインで使用される収集フレームワークのクラスおよびインタフェース


図4-2の説明が続きます
「図4-2 収集プラグインで使用される収集フレームワークのクラスおよびインタフェース」の説明

4.5 Javaベースの収集プラグインの作成方法

Oracle Data VaultのJavaベースの収集プラグインの作成と使用に必要なタスクを確認します。

4.5.1 Javaベースの収集プラグインの作成について

Oracle Audit Vaultのドキュメントには、イベントをAUDという名前の表に書き込む仮のソースなどを含めて、Javaベースの収集プラグインの実装例が示されています。

Oracle Audit Vault and Database Firewallの実装には、AuditEventCollectorFactoryインタフェースを実装するJavaクラスの記述、およびAudit Vault収集フレームワークの一部であるAuditEventCollectorクラスの拡張が含まれます。同じJavaクラスを使用して、AuditEventCollectorクラスの拡張と、AuditEventCollectorFactoryインタフェースの実装の両方を実行できます。または、個別に2つのクラスを記述することもできます。サンプルは、AuditEventCollectorFactoryインタフェースを実装するSampleEventCollectorFactoryと、AuditEventCollectorクラスから拡張されるSampleEventCollectorの、2つのクラスで構成されます。

4.5.2 AuditEventCollectorFactoryを使用したAuditEventCollectorオブジェクトの取得

収集フレームワークはAuditEventCollectorオブジェクトのインスタンスを直接作成しません。かわりに、AuditEventCollectorFactoryクラスのインスタンスを作成し、ファクトリ・オブジェクトを使用してAuditEventCollectorオブジェクトを取得します。これは、収集プラグインでAuditEventCollectorの複数の実装が必要になる可能性があるためです。どの実装を使用するかは、収集プラグインによって実行時に決定されます。そのため、すべての収集プラグインにAuditEventCollectorFactoryが実装されている必要があります。

例4-1では、createAuditEventCollector()は常にSampleAuditEventCollectorクラスのインスタンスを作成して返します。

例4-1 SampleAuditEventCollectorクラスの作成

public class SampleEventCollectorFactory implements AuditEventCollectorFactory {
 
   public AuditEventCollector createAuditCollection(
         CollectorContext collectorContext) throws AuditEventCollectorException {
      return new SampleEventCollector();
   }
}

4.5.3 Javaベースの収集プラグイン作成時のCollectorContextクラスの使用

監査証跡の効率的な収集に必要なソースに関する情報をOracle Data Vault収集プラグインに提供するソース属性の使用方法を学習します。

収集フレームワークは、initializeCollectorメソッドを使用して、CollectorContextクラスのインスタンスを収集プラグインに渡します。収集プラグインは、このインスタンスを問い合せて、ソースが生成した監査証跡の収集に必要な情報を取得します。

4.5.3.1 基本ソース属性

監査証跡収集を正常に取得するために、収集プラグインにOracle Audit Vault and Database Firewallのソースに関する情報を提供する基本ソース属性があります。

Oracle Audit Vault and Database Firewallの基本ソース属性には、ユーザー名、パスワードおよび接続文字列が含まれます。これらの属性は、それぞれgetSecuredTargetUsergetSecuredTargetPasswordおよびgetSecuredTargetLocationの各メソッドにより返されます。他のソース属性はgetAttributesを使用して取得できます。

Oracle Audit Vault管理者がソースを登録する場合、Oracle Audit Vault管理者に必要な情報をソース属性の形式で指定するように要求できます。Oracle Audit Vaultでは、これらの属性はOracle Audit Vault Serverリポジトリに保存され、起動時にコレクタ・コードに提供されます。

一部の収集プラグインではソースへの接続が不要であり、その場合、収集フレームワークはこれらのメソッドにnullを返します。

4.5.3.2 基本証跡属性

チェックポイントおよび証跡名の属性は、Oracle Audit Vault and Database Firewallで取得される基本属性です。

チェックポイントの属性はgetCheckpointメソッドによって返され、証跡名の属性はgetTrailLocationメソッドによって返されます。これらの属性は収集プラグインで次のように使用されます。

  • 返されたチェックポイントは、収集プラグインが最後に実行されたときに、この証跡用に設定した最後のチェックポイントです。収集プラグインは、イベント時間がチェックポイント以降であるレコードのみの送信を開始します。収集プラグインを初めて開始する場合、収集プラグインはこの値をnullとして受け取ります。この場合、収集プラグインはレコードを最初から送信する必要があります。

  • 証跡名は、監査イベントが含まれるターゲットを示しており、通常は表またはディレクトリの名前です。

他の証跡属性はgetAttributesを使用して取得できます。

4.5.3.3 ユーティリティ・インスタンス

AVLoggerおよびAuditService属性をOracle Audit Vaultコレクタで使用する方法を学習します。

AVLoggerおよびAuditServiceは、それぞれgetLoggerメソッドおよびgetAuditServiceメソッドによって返されます。これらの属性はコレクタで次のように使用されます。

  • AVLoggerインスタンスは様々なメッセージを記録します。

  • AuditServiceインスタンスはチェックポイントおよびメトリックをAudit Vault Serverに送信します。

これらのメソッドがnullを返すことはありません。

4.5.3.4 その他のソースまたは証跡属性

コレクタに必要なその他の属性は、属性名をgetAttributeメソッドに渡すことによって返されます。

たとえば、監査データを収集するために、ソースにSourceVersionが必要である場合、ソースのコレクタはcollectorContext.getAttribute('SourceVersion')を呼び出して、SourceVersionの値を取得します。

属性が存在する場合、getAttributeメソッドは属性値を文字列として返します。そうでない場合、メソッドはnullを返します。

必須の属性にnullまたは無効な値を受け取った場合、コレクタはinitializeCollectorメソッドからAuditEventCollectorException例外をスローします。その後、収集フレームワークは停止します。

関連項目:

収集プラグイン属性の実行時変更の詳細は、「Audit Vault and Database Firewall属性の実行時変更」を参照してください

4.5.4 Javaベースの収集プラグインの初期化

これらの例は、Javaベースの収集プラグインを初期化する方法と、Oracle Audit Vault and Database Firewallを使用してイベントの収集を開始する方法を理解する場合に使用します。

収集スレッドの開始後に収集フレームワークが最初に行うことは、コレクタの初期化です。

収集フレームワークは、AuditEventCollectorクラスのinitializeCollector()メソッドを呼び出します。コレクタは環境を適切に設定し、監査イベントの収集を開始できるようにします。たとえば、データベース表の収集プラグインの場合、このメソッドはデータベースに接続します。XMLファイルの収集プラグインの場合、このメソッドはファイル・マスクを解析し、開始する特定のファイルを開きます。収集プラグインはまた、このときに様々な属性をコレクタ・コンテキストから取得する場合があります。環境の設定中にエラーが発生した場合、このメソッドは適切なエラー・メッセージとともにAuditEventCollectorExceptionをスローします。

例4-2 Javaベースの収集プラグインの初期化

次に、Javaベースの収集プラグインを初期化する方法の例を示します。

private AVLogger m_logger;
   private CollectorContext m_collectorContext;
   private long m_timeZoneOffset;
   private AuditService m_auditService;
   private Timestamp m_previousCheckpoint;
 
   public void initializeCollector(CollectorContext collectorContext)
         throws AuditEventCollectorException {
      m_collectorContext = collectorContext;
      m_auditService = m_collectorContext.getAuditService();
      m_previousCheckpoint = m_collectorContext.getCheckpoint();
      m_logger = m_collectorContext.getLogger();
      // Get other attributes of the Source.
      String offset = m_collectorContext.getAttribute("TimeZoneOffset");
      if (offset != null) {          m_timeZoneOffset = getTimeZoneOffsetInMs(offset);
      }
      connectToSource();
 }

例4-3 ConnectionManagerユーティリティを使用したデータベースの接続と監査レコードの取得

監査レコードを取得するためにコレクタをデータベースに接続する必要がある場合は、Oracle Audit Vaultで提供されるConnectionManagerユーティリティAPIを使用する必要があります。次の例は、ConnectionManagerユーティリティの使用方法を示しています。

private ConnectionManager m_connectionManager;
   
   private void connectToSource() throws AuditEventCollectorException {
      m_logger.logDebugMethodEntered();
      // Get connection information from collector context.
      String user = m_collectorContext.getSecuredTargetUser();
      String password = new String(m_collectorContext.getSecuredTargetPassword());
      String connectionString = m_collectorContext.getSecuredTargetLocation();
      // Create a ConnectionManager object.
      try {
         m_connectionManager = new ConnectionManagerImpl(connectionString,
               user, password.toCharArray());
         m_connection = m_connectionManager.getConnection();
      } catch (AuditException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.FAILED_CONNECT_TO_SOURCE,
               new Object[] { connectionString }, ex);
      }
      m_logger.logDebugMethodExited();
   }

4.5.5 接続、イベントのフェッチおよびチェックポイントの設定

初期化後、収集フレームワークは、内部的にfetchEvents()メソッドを呼び出す、コレクタのhasNext()メソッドを繰り返し呼び出します。このメソッドでは、コレクタは監査証跡から監査レコードをResultSetの形式でフェッチします。

フェッチされる範囲は、現在の時間に近く、終了したばかりの時点から開始します。次のフェッチは、現在のResultSetを使い果たしたときに実行されます

収集プラグインは、1つのResultSetの処理が終了すると、次が始まる前にチェックポイントを設定します。このタイミングは重要です。収集プラグインがTimestamp tでチェックポイントを設定した場合、tより前のイベント時間を持つすべてのレコードが収集フレームワークにすでに送信されていることを確認する必要があります。ただし、ResultSetではレコードに特定の順序付けを行わないため、ResultSetの終了前にチェックポイントを設定するのは正しくありません。また、収集プラグインでは現在の時間を範囲の上限として使用せず、現在の時間からデルタ時間を引いた時間を使用します。これにより、イベントの生成とイベントを表に挿入するまでの間の遅延が許容されます。収集プラグインが問合せを実行した場合、上限までのすべてのイベントがResultSetにフェッチされ、チェックポイント・コントラクトが履行されます。5秒の遅延時間(デルタ)によって、上限までのすべてのレコードがすでに表にあることを確認できます。

例4-4に示すように、コレクタが必要とする場合は常にConnectionManagerからConnectionを取得できる必要があります。

例4-5では、hasNext()メソッドは、例4-4で定義したfetchEvents()メソッドを実行して、レコードのフェッチとチェックポイントの設定を行います。

例4-4 ResultSetのフェッチおよびチェックポイントの設定

   private ResultSet m_resultSet;
   private Timestamp m_nextCheckpoint;
 
   private void fetchEvents() throws AuditEventCollectorException {
      m_logger.logDebugMethodEntered();
      if (m_nextCheckpoint != null) {
         m_auditService.setCheckpoint(m_nextCheckpoint);
         m_previousCheckpoint = m_nextCheckpoint;
      }
     // It is not good to hold on to the Connection for long. As this is the
      // only place we can release the connection, we release and reacquire the
      // connection.
      try {
         if (m_connection != null) {
            m_connectionManager.releaseConnection(m_connection);
         }
      } catch (AuditException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.FAILED_TO_RELEASE_CONNECTION_TO_DB, null, ex);
      }
 
      try {
         m_connection = m_connectionManager.getConnection();
      } catch (AuditException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.FAILED_TO_GET_CONNECTION_TO_DB, null, ex);
      }
 
     // This is the upper bound which is current time minus 5 seconds.
      m_nextCheckpoint = new Timestamp(System.currentTimeMillis() - 5000);
     String query = null;
      try {
         if (m_previousCheckpoint == null) {
            query = "select * from AUD where EVENT_TIME <= ?";
            m_preparedStatement = m_connection.prepareStatement(query);
            m_preparedStatement.setTimestamp(1, m_nextCheckpoint);
         } else {
            query = "select * from AUD where EVENT_TIME > ? and EVENT_TIME <= ?";
            m_preparedStatement = m_connection.prepareStatement(query);
            m_preparedStatement.setTimestamp(1, m_previousCheckpoint);
            m_preparedStatement.setTimestamp(2, m_nextCheckpoint);
         }
         m_resultSet = m_preparedStatement.executeQuery();
      } catch (SQLException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE,
               new Object[] { query }, ex);
      }
      m_logger.logDebugMethodExited();
   }

例4-5 hasNextを使用したレコードのフェッチ

     public boolean hasNext() throws AuditEventCollectorException {
      boolean hasMore;
      try {
         if(m_resultSet == null) {
            fetchEvents();
            return m_resultSet.next();
         }
         hasMore = m_resultSet.next();
         if (!hasMore) {
            fetchEvents();
            hasMore = m_resultSet.next();
         }
      } catch (SQLException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
      }
      return hasMore;
   }

4.5.6 ソース・イベント値のAudit Vaultイベント値への変換

Oracle Audit Vault収集プラグインがソース・イベント値をいつどのようにしてOracle Data Vault値に変換するかについて学習します。

コレクタは、ソースから特定のフィールドの値を取得します。一部のフィールドについては、値を取得するだけでなく、特定の方法で値を変換する必要があります。この項では、すべてのソース・タイプに対して必要な変換について説明します。

4.5.6.1 イベント時間からUTC

イベント時間はUTCタイムゾーンでのみ送信できます。そのため、値を返す前にソース・タイムゾーンからUTCタイムゾーンに変換する必要があります。ソース・データベースの列でタイムゾーンが認識される場合、この変換は必要ありません。

例4-6 EventTimeのソース・タイムゾーンからUTCへの変換

   public Timestamp getEventTimeUTC() throws AuditEventCollectorException {
      try {
         Timestamp eventTime = m_resultSet.getTimestamp("EVENT_TIME");
         // As the method name suggests, the timestamp must be returned only in
         // UTC timone.
         return new Timestamp(eventTime.getTime() - m_timeZoneOffset);
      } catch (SQLException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
      }
   }

4.5.6.2 ソース・イベント名からAudit Vaultイベント名

各ソース・イベント名は、1つのAudit Vaultイベント名にマップされます。getCommandClass()メソッドは、ソース・イベント名をAudit Vaultが受け入れられる値に変換します。

例4-7 ソース・イベント名からAudit Vaultイベント名へのマッピング

private static final Map<Integer, String> eventNameMap = new HashMap<Integer,
         String>();
static {
      eventNameMap.put(1, "CREATE");
      eventNameMap.put(2, "INSERT");
      eventNameMap.put(3, "SELECT");
      eventNameMap.put(4, "CREATE");
      eventNameMap.put(15, "ALTER");
      eventNameMap.put(30, "AUDIT");
      eventNameMap.put(34, "CREATE");
      eventNameMap.put(35, "ALTER");
      eventNameMap.put(51, "CREATE");
      eventNameMap.put(52, "CREATE");
   }
 
   public String getCommandClass() throws AuditEventCollectorException {
      try {
         int eventId = m_resultSet.getInt("ACTION");
         return eventNameMap.get(eventId);
      } catch (SQLException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
      }
   }

関連項目:

Audit Vaultイベント名の一覧は、Oracle Audit Vault and Database Firewallフィールドを参照してください。

4.5.6.3 ソース・イベントIDからソース・イベント名

一部のソースでIDとしてレポートされるイベントは、ユーザーがIDを熟知していなければ意味を持ちません。そのため、ソース・イベントIDをわかりやすいソース・イベント名にマップするのが最良の方法です。監査レコード自体にわかりやすいイベント名が付けられている場合は、マッピングせずに直接返すことができます。ソース・イベント名はオプションであるため、情報がない場合、収集プラグインはnullを返します。

例4-8では、ソース・イベントIDをわかりやすいソース・イベント名にマップします。

例4-8 ソース・イベントIDからソース・イベント名へのマッピング

private static final Map<Integer, String> sourceEventMap = 
        new HashMap<Integer, String>();
 
   static {
      targetTypeMap.put(1, "OBJECT:CREATED:TABLE");
      targetTypeMap.put(2, "INSERT INTO TABLE");
      targetTypeMap.put(3, "SELECT FROM TABLE");
      targetTypeMap.put(4, "OBJECT:CREATED:TABLE");
      targetTypeMap.put(15, "OBJECT:ALTERED:TABLE");
      targetTypeMap.put(30, "AUDIT OBJECT");
      targetTypeMap.put(34, "OBJECT:CREATED:DATABASE");
      targetTypeMap.put(35, "OBJECT:ALTERED:DATABASE");
      targetTypeMap.put(51, "OBJECT:CREATED:USER");
      targetTypeMap.put(52, "OBJECT:CREATED:ROLE");
   }
 
   public String getEventName() throws AuditEventCollectorException {
      try {
         int eventId = m_resultSet.getInt("ACTION");
         return sourceEventMap.get(eventId);
      } catch (SQLException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
      }
   }

4.5.6.4 ソース・イベント名またはIDからターゲット・タイプへのマッピング

ターゲット・タイプは、イベントが発生したオブジェクトのタイプです。たとえば、イベントが表のSELECT操作である場合、ターゲット・タイプは表です。一部のソースでは、ソース・イベント名およびIDでターゲット・タイプを表している場合があります。たとえば、イベント名select tableでは、ターゲット・タイプが表であることを示しています。この場合、ソース・イベント名またはIDをターゲット・タイプにマップする必要があります。ターゲット・タイプはオプションのフィールドであるため、そのような情報がない場合、収集プラグインはnullを返します。

例4-9では、ソース・イベントIDをAudit Vaultターゲット・タイプにマップしています。

例4-9 ソースIDからターゲット・タイプへのマッピング

private static final Map<Integer, String> targetTypeMap = 
      new HashMap<Integer, String>();
 
   static {
      targetTypeMap.put(1, "TABLE");
      targetTypeMap.put(2, "TABLE");
      targetTypeMap.put(3, "TABLE");
      targetTypeMap.put(4, "CLUSTER");
      targetTypeMap.put(15, "TABLE");
      targetTypeMap.put(30, "OBJECT");
      targetTypeMap.put(34, "DATABASE");
      targetTypeMap.put(35, "DATABASE");
      targetTypeMap.put(51, "USER");
      targetTypeMap.put(52, "ROLE");
   }
 
   public String getTargetType() throws AuditEventCollectorException {
      try {
         int eventId = m_resultSet.getInt("ACTION");
         return targetTypeMap.get(eventId);
      } catch (SQLException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
      }
   }

4.5.6.5 ソース・イベント・ステータスからAudit Vaultイベント・ステータス

EventStatusに許可される値は3つのみです。SUCCESSFAILUREおよびUNKNOWNです。例4-10に示すように、ソース値をこれらの値のいずれかにマップする必要があります。

例4-10 ソース値からAudit Vault EventStatus値への変換

   public EventStatus getEventStatus() throws AuditEventCollectorException {
      try {
         int status = m_resultSet.getInt("STATUS");
         if (status == 1) {
            return EventStatus.SUCCESS;
         } else if (status == 0) {
            return EventStatus.FAILURE;
         } else {
            return EventStatus.UNKNOWN;
         }
      } catch (SQLException ex) {
         throw new AuditEventCollectorException(
            ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
      }
   }

4.5.7 その他の監査フィールド値の取得

変換の必要がないフィールドについては、収集プラグインはソースから取得した値を返します(例4-11ではユーザー名を取得し、これを返しています)。

例4-11 変換不要の値を返す

   public String getUserName() throws AuditEventCollectorException {
      try {
         return m_resultSet.getString("USER_ID");
      } catch (SQLException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
      }
   }

4.5.8 Audit Vault and Database Firewall属性の実行時変更

Oracle Audit Vault and Database Firewall管理者は、Audit Vault and Database FirewallコンソールまたはAVCLIコマンドライン・ツールを使用して、ソース属性などの属性を実行時に更新できます。

コレクタが監査証跡を収集しているときに更新が発生した場合、Audit Vault ServerはコレクタのsetAttributeメソッドを呼び出して、実行中のすべてのコレクタに対して動的に通知を行います。その後、収集プラグインはただちに新しい値を使用して開始する必要があります。収集プラグインが属性を認識できない、または使用できない値である場合、コレクタはSetAttributeExceptionをスローします。

例4-12では、収集プラグインは、以降のすべてのイベントでEventTimeからUTCタイムゾーンに変換する際に使用する、新しいタイムゾーン・オフセットを受け取り、処理します。これは、例4-6で発生するタイムゾーン・オフセットの変換に影響を与えます。

関連項目:

例4-12 Audit Vault and Database Firewall属性の変更

public void setAttribute(String name, String value)
         throws SetAttributeException {
           if (name.equalsIgnoreCase("TimeZoneOffset")) {
              m_timeZoneOffset = getTimeZoneOffsetInMs(value);
      } else {
         throw new SetAttributeException(ErrorCodes.INVALID_ATTRIBUTE_NAME,
               new Object[] { name, value }, null);
      }
   }

4.5.9 カスタム属性の実行時変更

AVDF属性と同じように、カスタム属性を実行時に変更することができます。

カスタム属性を変更する場合は、次のメソッドを実装して、setAttributeメソッドで使用する前にカスタム属性を検証する必要があります。

例4-13 カスタム値の変更

private static final String[] s_attributes = new String[] { "av.collector.configureParameter1", "av.collector.configureParameter2" };
public String[] getAttributeNames() throws AuditEventCollectorException {
         return s_attributes.clone();
 }
 
public void setAttribute(String name, String value)
         throws SetAttributeException {
           if (name.equalsIgnoreCase("configureParameter1")) {
           // use value
           }else if (name.equalsIgnoreCase("configureParameter2"))
           {
           // use value
           }else {
         throw new SetAttributeException(ErrorCodes.INVALID_ATTRIBUTE_NAME,
               new Object[] { name, value }, null);
      }
   }

4.5.10 拡張フィールドの作成

拡張フィールドには、ユーザーが関心を持っていているがコア・フィールドまたはラージ・フィールドのいずれにも対応していない、ソース・イベントのすべてのフィールドが含まれます。コレクタには、これらの追加フィールドの名前と値を含む文字列が1つ構成されている必要があります。この文字列の書式は収集プラグインで決定できます。収集フレームワークがこの文字列を解析することはありません。例4-14では次の書式を使用し、必要に応じて繰り返します。

 <field_name>=<field_value>;

例4-14では、拡張の一部として3つのフィールドを送信します。

例4-14 拡張フィールドの作成

  public String getExtension() throws AuditEventCollectorException {
      try {
         StringBuilder sb = new StringBuilder();
         sb.append("DB_ID=" + m_resultSet.getString("DB_ID") + ";");
         sb.append("INSTANCE=" + m_resultSet.getString("INSTANCE") + ";");
         sb.append("PROCESS=" + m_resultSet.getString("PROCESS"));
         return sb.toString();
      } catch (SQLException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
      }
   }

4.5.11 監査ラージ・フィールドの処理

一部の監査レコード・フィールドは非常に大きく、文字列として返すことができない場合があります。そのため、これらのフィールドに対応するメソッドは、Readerタイプのオブジェクトを返します。ソース・フィールドがCLOBである場合、clob.getCharacterStream()を使用してReaderを取得できます。

ノート:

Readerは、ソースへの接続が活動状態である間のみ有効です。

リーダーを使用するすべてのイベントがAudit Vault Serverに送信されるまで、ソースへの接続が活動状態に維持されるように、収集プラグインを設計する必要があります。

コレクタでソースへのConnectionをリセットする場合は、チェックポイントの設定直後に行う必要があります。これは、収集フレームワークがレコードのバッチを送信してからチェックポイントを設定するため、すべてのレコードが確実にAudit Vault Serverに送られているのはこの時点のみであるからです。この他にも、レコードがAudit Vault Serverに送信されている状況はありますが、チェックポイントを含めるとこの場合のみであることに注意してください。

Readerインスタンスを直接取得できない場合は、コレクタがReaderを作成して返す必要があります。

例4-15 ラージ・フィールドの作成

   public Reader getCommandText() throws AuditEventCollectorException {
      try {
         Clob clob = m_resultSet.getClob("SQL_TEXT");
         return clob.getCharacterStream();
      } catch (SQLException ex) {
         throw new AuditEventCollectorException(
               ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
      }
   }

4.5.12 レコードの一意識別用のマーカーの作成

コレクタは、収集フレームワークがレコードを一意に識別するために使用するマーカーを生成する必要があります。

コレクタは、特定の証跡の各レコードに一意のマーカーを生成する必要があります。マーカーの作成には2つ以上のイベント・フィールドを使用できます。テンプレートベースの収集プラグインでない場合は、表名、ファイル名、ファイル作成時間などの、監査イベントに含まれていない情報を使用することもできます。作成にかかる時間が短く、リカバリ・フェーズでのスペースが少なく、また一致時間が短くなるため、小さいサイズのマーカーが推奨されます。マーカーは、最後のチェックポイント後に送信されたレコードをフィルタする必要があるような、特にリカバリフェーズの特定のシナリオに有用です。収集プラグインはイベントの収集を開始する場合、最後の実行の最後のチェックポイントから開始します。ただし、そのチェックポイントの後に一部のレコードが収集され、Audit Vault Serverに送信されている可能性があります。重複を避けるために、収集フレームワークはレコード・マーカーを使用して、受信レコードとAudit Vault Serverにある既存のレコードを比較します。

例4-16では、マーカーのSession_IDおよびEntry_IDを使用します。

例4-16 マーカーの作成

public String getMarker() throws AuditEventCollectorException {
      // ENTRY_ID will identify an audit event uniquely with in a session. Hence
      // ENTRY_ID along with SESSION_ID will uniquely identify an audit event
      // across sessions.
      try {
         return m_resultSet.getString("SESSION_ID") + ":"
               + m_resultSet.getString("ENTRY_ID");
      } catch (SQLException ex) {
           throw new AuditEventCollectorException(
               ErrorCodes.ERROR_GETTING_DATA_FROM_SOURCE, null, ex);
      }
   }

4.5.13 Javaベースの収集プラグインを閉じる

Javaベースの収集プラグインを閉じるプロセスは、収集フレームワークが特定の監査証跡の収集を停止するコマンドを受信したときに開始され、収集フレームワークはclose()メソッドを使用してコレクタにこれを通知します。このメソッドでは、コレクタはデータベース接続またはファイル処理の終了などのクリーンアップ・タスクを実行します。close()メソッドから収集フレームワークに制御が戻されると、収集スレッドは終了します。

このメソッドが例外をスローすることは予期されていません。例4-17に示すように、例外が発生した場合はエラー・メッセージが記録されます。

例4-17 クローズの呼出しおよびリソースの解放

public void close() {
      try {
         if (m_resultSet != null) {
            m_resultSet.close();
            m_resultSet = null;
         }
         if (m_connectionManager != null) {
            m_connectionManager.destroy();
            m_connectionManager = null;
         }
         m_previousCheckpoint = null;
         m_nextCheckpoint = null;
         m_logger = null;
      } catch (SQLException ex) {
         m_logger.logError("SampleEventCollector", "close",
               "SQLException occurred. ", ex);
      } catch (AuditException ex) {
         m_logger.logError("SampleEventCollector", "close",
               "AuditException occurred. ", ex);
      }
   }  

4.5.14 収集プラグインでの例外の使用

コレクタは、次の2つのチェック済例外をスローします。AuditEventCollectorExceptionおよびSetAttributeExceptionsetAttributeメソッドは、新しい値を設定できない場合にSetAttributeException例外をスローします。この例外が受信されると、場合によってはコレクタが収集フレームワークによって停止されます(例4-12を参照)。closeメソッド以外のすべてのメソッドはAuditEventCollectorExceptionをスローします。この例外は、回復不能な条件が発生した場合にのみスローされるようにします。この例外を受信すると、収集フレームワークはコレクタを停止します。コレクタを停止する前に、収集フレームワークはcloseメソッドを呼び出します。これらの例外を作成しスローするサンプル・コードについては、前の項を参照してください。

4.6 Javaベースの収集プラグインのユーティリティAPI

収集フレームワークに加えて、Oracle Audit Vault APIにはコレクタの記述タスクを簡単にするJavaユーティリティAPIが含まれています。

4.6.1 ConnectionManager APIを使用したデータベース・ソースへの接続について

Javaで記述されたOracle Audit Vault and Database Firewallのコンポーネント(コレクタ、エージェントおよびサーバー)はすべて、ConnectionManager APIを使用してデータベースへの接続を管理する必要があります。

ConnectionManager APIを使用して、Oracle Database、Microsoft SQL Server、Sybase Adaptive Server、およびIBM DB2などのソース・データベースへの接続を管理します。

ConnectionManager APIを使用する利点

  • データベース・サーバーのリソースの使用率が下がります。

  • クライアント側の操作がより正常になり、クライアントがハングしたり突然強制終了されることはなくなります。

  • これによりパフォーマンスが改善されます。

接続プールの設定に必要となる適切なパラメータが設定された、接続マネージャの具体的な実装をインスタンス化する必要があります。いくつかのコンストラクタを使用できます。呼出し元によって指定されないオプション・パラメータはすべて、次に示すようにOracle Audit Vault固有のデフォルト値になります。

  • CONNECTION_FACTORY_CLASSNAME=oracle.jdbc.pool.OracleDataSource

  • MIN_POOL_SIZE=0

  • INACTIVE_CONNECTION_TIMEOUT=1800

  • INITIAL_POOL_SIZE=0

  • VALIDATE_CONNECTION_ON_BORROW=true

4.6.2 ConnectionManager APIを使用したデータベース・ソースへの接続の例

ConnectionManager APIを使用してデータベースへのOracle Audit Vault and Database Firewall Javaコンポーネント接続を管理する方法を確認してください。

ConnectionManager APIは、データベース接続を管理するための取得、使用および解放モデルに基づいています。Javaで記述されたOracle Audit Vault and Database Firewallのコンポーネント(コレクタ、エージェントおよびサーバー)はすべて、ConnectionManager APIを使用してデータベースへの接続を管理する必要があります。
呼出し元には、次のステップを示した順序で完了することが期待されます。
  1. ConnectionManager APIのインスタンスを作成します。
  2. データベースへの接続を取得します。
  3. 接続を使用します
  4. 接続を解放してプールに戻します。
  5. 必要に応じて、ステップ2から4を繰り返します。
  6. 接続マネージャ・インスタンスを破棄します。

例4-18 接続マネージャを使用した接続プールの処理

//Connection Manager
ConnectionManager cManager = null;
 
try {
  /*
   * Connection Pool Properties.
   * Set the pool properties such as URL
   * Initial pool size, Min pool size, etc.
   * The set of supported connection pool properties are
   * documented in the Oracle UCP documentation
   */
  Properties pProps = new Properties(); 
  pProps.put(URL, "jdbc:oracle:thin:@hostname:port:sid");
 
  /*
   *  Connection Properties
   *
   *  Set the connection properties here.
   *  The set of connection properties that can be set
   *  depends on the driver.  To enable SSL using the
   *  the oracle jdbc driver, you need to set the following
   *     Properties cProps = new Properties();
   *     String walletLoc =    "/path/to/walletdirectory/cwallet.sso";
   *     cProps.setProperty("oracle.net.authentication_services","(TCPS)");
   *     cProps.setProperty("javax.net.ssl.trustStore", walletLoc);
   *     cProps.setProperty("oracle.net.ssl_server_dn_match", "true")  ;
   *     cProps.setProperty("javax.net.ssl.trustStoreType","SSO");
   *     cProps.setProperty("javax.net.ssl.keyStore", walletLoc);
   *     cProps.setProperty("javax.net.ssl.keyStoreType","SSO");
   */
  Properties cProps = new Properties();
 
  cManager =  new ConnectionManagerImpl(pProps, cProps);
           
  String username;
  char[] passwd;
  Connection conn = null;
 
  /* Do something */
  ...
 
  /* Retrieve and set the username and password for user1 */
  username = "user1";
  passwd   = "user1passwd".toCharArray();
 
  /* Get a connection as "user1"*/
  conn = cManager.getConnection(username, passwd);      
 
 
  /* Use the "user1" connection and do something useful */
  ...         
 
  /* Release the connection */
  cManager.releaseConnection(conn);
          
  /* Retrieve and set the username and password for user2 */
  username = "user2";
  passwd   = "user2passwd".toCharArray();
 
  /* Get a connection as "user2" */
  conn = cManager.getConnection(username, passwd);      
 
 
  /* Use the "user2" connection and do something useful */
  ...         
 
  /* Release the connection */
  cManager.releaseConnection(conn);
 
} catch (Exception e) {
  /* Take appropriate action here */
 
} finally {
  if (cManager != null) {
    try {
      cManager.destroy();
    } catch (AuditException ae) {
      /* Take appropriate action here */
    }
} 

ConnectionManager APIは、呼出し元が異なるユーザー資格証明を使用していつでもデータベース接続を取得し解放できるように設計されています。たとえば、呼出し元はaliceのデータベース資格証明を使用して接続を取得し、その後robertのデータベース資格証明で同じ接続マネージャを使用して接続を取得できます。

ノート:

呼出し元は次のことを行わないでください。

  • 接続への参照をローカルに保持する(インスタンスまたはクラス変数を介して)。
  • 接続を長時間保留にする。

これらの要件によって、接続プールは次のような動作の接続を自動的に回復できるようになります。

  • TIME_TO_LIVE時間制限を超過した。
  • 放棄された、つまり、しばらく使用されていない接続。
  • 流用された回数が多すぎる接続。この要件によってリソース・リークが確実に回避されます。

4.6.3 Windowsイベント・ログ・アクセスAPIの使用

Microsoft Windowsイベント・ログを解析するには、Microsoft WindowsのEventLog APIを使用できます。

Windows EventLog APIは、Windowsイベント・ログにアクセスするWindows API上のラッパーです。このAPIは、監査レコードの抽出が必要なコレクタを対象として、Windowsプラットフォーム上でのみ使用可能です。

次の図は、Windowsイベント・ログの解析に使用できるクラスを示しています。

図4-3 Windowsイベント・ログの構造


図4-3の説明が続きます
「図4-3 Windowsイベント・ログの構造」の説明

EventLogRecordクラスによって、イベント・ログに1つのレコードを格納できます。EventLogReaderクラスによって、イベント・ログ・レコードを1つずつフェッチできます。演算子クラスによって、イベント・ログ・レコードをフィルタできます。演算子は、イベント・ログ・レコードの特定のフィールドで動作し、フィールドの値に基づいてレコードをフィルタするかどうかを決定します。たとえば、Equals演算子を使用して、フィールドの値が指定した値と等しくないすべてのイベント・ログ・レコードをフィルタできます。InRange演算子およびOutsideRange演算子は三項演算子です。その他は二項演算子です。

イベント・ログ・レコードを収集するには、次のステップを実行します。

  1. EventLogReaderインスタンスを作成します。

    たとえば、アプリケーション・イベント・ログを開くには、次のようにします。

    EventLogReader eventLogReader = new EventLogReader();
    eventLogReader.openLog()
    

    セキュリティまたはシステムのイベント・ログなど、その他のイベント・ログを開くには、オーバーロード・メソッドopenLog(String log)を使用します。たとえば、セキュリティ・イベント・ログを開くには、次のようにします。

    EventLogReader eventLogReader = new EventLogReader();
    eventLogReader.openLog("Security");
    

    アプリケーション・イベント・ログを特定のレコード番号から開くには、openLog(int startRecNum)オーバーロード・メソッドを使用します。たとえば、アプリケーション・イベント・ログを監査レコード番号1234から開くには、次のようにします。

    EventLogReader eventLogReader = new EventLogReader();
    eventLogReader.openLog(1234);
    

    セキュリティまたはシステムのイベント・ログを特定のレコード番号から開くには、オーバーロード・メソッドのopenLog(String log, int startRecNum)を使用します。たとえば、セキュリティ・イベント・ログをレコード番号4321から開くには、次のようにします。

    EventLogReader eventLogReader = new EventLogReader();
    eventLogReader.openLog("Security",4321);
    
  2. 適切なフィルタを追加します。

    たとえば、SourceNameフィールドにequalsフィルタをバインドして、EventLogReaderがソース名MSSQL$SQLEXPRESSのレコードのみを受信するようにするには、次のようにします。

    eventLogReader.addFilter(EventLogReader.SOURCE_NAME,
    Equals.getInstance(), "MSSQL$SQLEXPRESS");
    

    Timestamp, m_lowerBoundTime,とm_upperBoundTime,の間のイベント・レコードのみを取得するには、次のフィルタを使用します。

    m_eventLogReader.addFilter(EventLogReader.TIME_GENERATED, GreaterThan.getInstance(), m_lowerBoundTime);
    
    m_eventLogReader.addFilter(EventLogReader.TIME_GENERATED, LessThan.getInstance(), m_upperBoundTime);
    
  3. EventLogRecordをフェッチして処理します。

    次のサンプル・コードでは、次のEventLogRecordを取得し、そこから様々なフィールドを抽出します。

    if(eventLogReader.hasNext()) {
                  EventLogRecord record = (EventLogRecord)eventLogReader.next();
                  Long eventID = record.getEventId(); 
                  String userID = record.getUserSid();
                  String hostName = record.getComputerName();
      ...
       }
    
  4. EventLogReaderインスタンスを閉じます。

    コレクタが停止した場合は、次のコードを使用してEventLogReaderインスタンスをクローズします。

    eventLogReader.closeLog();

4.6.4 Windows EventMetaData APIの使用

イベントのメタデータを取得するには、このMicrosoft Windows Metadata Java APIプロシージャを使用できます。

Microsoft Windowsでは、バージョン2008以降、イベントのメタデータを取得できる新しいAPIが提供されています。パブリッシャ名を指定すると、このAPIは各イベントのメタデータを取得します。次の図は、Windows Metadata JavaがWindows API上のラッパーであることを示しています。

EventMetaDataRecordには、1つのイベントのメタデータが含まれます。EventMetaDataReaderを使用すると、イベント・メタデータ・レコードを1つずつフェッチできます。このAPIは次のように使用します。

  1. EventMetaDataReaderのインスタンスを作成します。
    EventMetaDataReader eventMetaDataReader = new EventMetaDataReader();
     
  2. パブリッシャのすべてのイベントのメタデータを取得します。
    Map<Long, List<EventMetaDataRecord>> eventLogRecordMap = eventMetaDataReader 
       getEventMetaData("Microsoft-Windows-Security-Auditing");
    
  3. マップから特定のイベントのメタデータ・リストを取得します。
    List<EventMetaDataRecord> eventRecordList = m_eventRecordMap
       get(m_eventLogRecord.getEventId());
    
  4. リストからメタデータを取得し、そこからイベント・データ名を取得します。
    EventMetaDataRecord eventMetaDataRecord = eventRecordList.get(i);
    for(int i=0; i<eventMetaDataRecord.getNumEventDataNames(); i++) {
       String eventDataName = eventMetaDataRecord.getEventDataName(i);
       ....
    }

4.6.5 AVLogger APIを使用したメッセージの記録

エラー、警告、情報、デバッグ・メッセージをOracle Audit Vault and Database Firewallログに記録するには、AVLogger APIを使用できます。

例4-19 AVLogger APIの使用

import oracle.av.platform.common.util.AVLogger;
import oracle.av.platform.common.exception.AuditException;
import oracle.av.platform.common.AuditErrorCodes;
 
public class Test
{
  public static void main(String[] args)  {
     /* Logger objects */
     AVLogger myModule = null;
     try {
       /* get Logger instances; this will auto-create the logger instance */
       /* if one does not exist */
       myModule = AVLogger.getLogger("someModule");
       /* print INFO level message */
       /* check log level if you are concatenating strings to avoid expensive */
       /* string operations */
       if(myModule.isInfoEnabled()) {
           avServer.logInfo("Testing INFO level message...." + "another String" +
             "one more string"); 
       }
       /* No need to check the log level if there is no string concatenation */
       myModule.logInfo("Testing INFO level message for another component....");
       /* changing the log level dynamically */
       myModule.setLogLevel(AVLogger.AV_LOG_LEVEL_DEBUG);
       myModule.logWarn("Testing WARN level message ....");
       myModule.logDebug("Testing DEBUG level message ....");
       /* Reset the log level back to INFO */
       myModule.setLogLevel(AVLogger.AV_LOG_LEVEL_INFO);
       /* Testing Exceptions: For now on, all exceptions will have */
       /* an OAV-XXXX error code printed out automatically as long as */
       /* they derive from AuditException object */
       throw new AuditException (ErrorCodes.INTERNAL_ERROR, null, null);
     } catch (Exception e) {
       myModule.logError(e);
     }
  }
}

4.6.6 Oracle XML Developer's Kitを使用したXMLファイルの解析

収集を開発している場合、Oracle XML Developer's Kitを使用してXMLファイルを解析し、そこから監査レコードを抽出できます。

Oracle XML Developer's Kitは含まれており、収集の開発に使用できます。

関連項目:

詳細は、『Oracle XML Developer's Kitプログラマーズ・ガイド』を参照してください。

4.7 Javaベースの収集プラグインでの監査証跡のクリーンアップの使用

監査証跡のクリーンアップは、アーカイブされた後に監査レコードを削除するために一部のソースが提供する機能です。このタイプの機能がソースに存在する場合、Audit Vault収集プラグインが統合して、ソースに監査証跡がアーカイブされた範囲を通知できます。これにより、ソースはそのポイントまでの監査証跡をクリーンアップ(元の監査データを削除)でき、これを認識しているとデータを損失しません。Audit Vault収集プラグインは、データが収集された最後のポイントのチェックポイントに関するクリーンアップ・ユーティリティ情報を提供します。

収集プラグインは、この情報を、agent_home\av\atcディレクトリの証跡固有の名前のファイルに、次の構文を使用して書き込みます。SecuredTargetName_TrailId.atc (oracl_1.atcなど)。

atcファイルの内容は次のようなものです。

  • securedTargetType=Oracle

  • SecuredTargetName=orcl

  • TrailType=TABLE

  • TrailName=sys.aud$

  • 2016-04-15 10:26:53.7 (このタイムスタンプは、これらの設定の最後のチェックポイントを表します。)

セキュア・ターゲットのクリーンアップ・ユーティリティは、atcのチェックポイントを解析し、このタイムスタンプまでの監査レコードを監査証跡から削除します。

たとえば、Oracle DatabaseソースはこのタイプのユーティリティをDMBS_AUDIT_MGMT PL/SQLパッケージで提供します。Oracle Databaseの事前パッケージ済収集プラグインをこのパッケージと統合することで、監査証跡のクリーンアップ操作が使用可能になります。

4.8 Javaベースの収集プラグインのセキュリティ上の考慮点

監査レコードを抽出するための接続が必要となるデータベースなどのソースについて、このタスクの実行に必要な権限を正しく文書化することは、開発者の責任です。接続に使用するアカウントには、ジョブに必要な最小限の権限のみを付与することをお薦めします。追加の権限を付与することは、セキュリティ上の問題になる可能性があります。

また、入力監査レコードを正しく解析し、Oracle Audit Vault and Database Firewallを悪意のあるデータから保護する必要があります。たとえば、監査レコードは、監査証跡にSQLまたはHTMLを挿入するように作成されており、これによってAVDFに保存されているデータに攻撃が加えられる危険があります。受信するすべての監査レコードは、収集フレームワークに渡される前に正しくサニタイズされる必要があります。