9 アプリケーション開発者のセキュリティの管理

アプリケーション開発者のセキュリティ・ポリシーでは、パスワード管理や外部プロシージャおよびアプリケーション権限の保護といった領域を網羅する必要があります。

9.1 アプリケーション・セキュリティ・ポリシーについて

アプリケーション・セキュリティ・ポリシーは、アプリケーション・セキュリティの要件およびデータベース・オブジェクトへのユーザー・アクセスを規制するルールのリストです。

安全なデータベース・アプリケーションを作成する最初のステップは、アプリケーション・セキュリティ・ポリシーの作成です。セキュリティ・ポリシーは、データベース・アプリケーションごとに立案する必要があります。たとえば、各データベース・アプリケーションには、アプリケーションの実行時に異なるレベルのセキュリティを提供する1つ以上のデータベース・ロールが必要です。データベース・ロールは、他のロールに付与するか、または特定のユーザーに直接付与できます。

(SQL*PlusやSQL Developerなどのツールを使用して)SQL文を制限なしで処理できるアプリケーションの場合でも、機密扱いのスキーマ・オブジェクトや重要なスキーマ・オブジェクトへの不当なアクセスを防ぐために、セキュリティ・ポリシーが必要です。特に、使用するアプリケーションでパスワードが安全に処理されることを確認する必要があります。

9.2 アプリケーション・ベースのセキュリティの使用に関する考慮事項

アプリケーション・セキュリティの実装では、アプリケーション・ユーザーとデータベース・ユーザーについて、アプリケーション内とデータベース内のどちらでセキュリティを強制するのかを検討する必要があります。

9.2.1 アプリケーション・ユーザーはデータベース・ユーザーでもあるか

できるかぎり、アプリケーション・ユーザーがデータベース・ユーザーであるアプリケーションを作成し、データベースに備わるセキュリティ・メカニズムを使用できるようにします。

多くの市販のパッケージ・アプリケーションでは、アプリケーション・ユーザーは、データベース・ユーザーではありません。これらのアプリケーションでは、複数のユーザーがユーザー自身をアプリケーションに対して認証し、次に、アプリケーションが単一の高い権限を持つユーザーとしてデータベースに接続します。これを、One Big Application Userモデルと呼びます。

この方法で作成されたアプリケーションは、通常、データベースに本来備わっているセキュリティ機能の多くを使用できません。これは、ユーザーの識別情報がデータベースで認識されないためです。ただし、クライアント識別子を使用して、いくつかのタイプの追跡を実行できます。たとえば、Oracle Call InterfaceのメソッドOCIAttrSetOCI_ATTR_CLIENT_IDENTIFIER属性を使用して、クライアント接続の監査と監視を有効にできます。クライアント識別子を使用すると、個々のWebユーザーの監査証跡データの収集、Webユーザーによるデータ・アクセスを制限するルールの適用、および各Webユーザーが使用しているアプリケーションの監視および追跡を行うことができます。

表9-1は、One Big Application Userモデルが様々なOracle Databaseセキュリティ機能にどのように影響するかを説明しています。

表9-1 One Big Application Userモデルの影響を受ける機能

Oracle Database機能 One Big Application Userモデルの制限

監査

セキュリティの基本原則の1つは、監査によるアカウンタビリティです。One Big Application Userがデータベース内のすべての操作を実行する場合、データベース監査では、個々のユーザーが実行したアクションに対する責任をそのユーザー自身に持たせることができません。アプリケーションでは、独自の監査メカニズムを実装して、ユーザーのアクションを個別に捕捉する必要があります。

Oracle厳密認証

データベースに対するクライアントの認証が、個々のユーザーではなくアプリケーションの場合、認証の厳密な形式(たとえば、SSLやトークンなどでのクライアント認証)は使用できません。

ロール

ロールは、データベース・ユーザーに割り当てられます。エンタープライズ・ロールは、データベース内で作成されていない場合でも、エンタープライズ・ユーザーに割り当てられ、データベースに認識されます。アプリケーション・ユーザーがデータベース・ユーザーではない場合、ロールの有用性は低くなります。この場合、アプリケーションでは独自のメカニズムを作成して、様々なアプリケーション・ユーザーがアプリケーション内のデータへアクセスするのに必要とする権限を識別する必要があります。

エンタープライズ・ユーザー管理

エンタープライズ・ユーザー管理機能は、Oracle Internet DirectoryなどのLDAPベースのディレクトリにユーザー情報を安全に格納して認可を管理することで、OracleデータベースがOracle Identity Managementインフラストラクチャを使用できるようにします。エンタープライズ・ユーザーは、データベース内に作成する必要はありませんが、データベースに認識される必要があります。One Big Application Userモデルでは、Oracle Identity Managementを利用できません。

9.2.2 アプリケーション内またはデータベース内でのセキュリティ規定

アプリケーションでできるだけ多くのデータベース・セキュリティ・メカニズムが使用されるようにすることをお薦めします。

ユーザーがデータベース・ユーザーでもあるアプリケーションは、アプリケーションの中にセキュリティを組み込むか、きめ細かい権限、仮想プライベート・データベース(アプリケーション・コンテキストによるファイングレイン・アクセス・コントロール)、ロール、ストアド・プロシージャ、および監査(ファイングレイン監査を含む)などのデータベースに本来備わっているセキュリティ・メカニズムを使用できます。

セキュリティがアプリケーション内ではなくデータベース自体で規定されている場合は、セキュリティを回避することはできません。アプリケーション・ベースのセキュリティの主なデメリットは、ユーザーがアプリケーションを回避してデータにアクセスすると、セキュリティが回避されることです。たとえば、データベースへのSQL*Plusアクセス権を持つユーザーは、人事管理アプリケーションを介さずに問合せを実行できます。したがって、このユーザーは、アプリケーション内のセキュリティ対策のすべてをバイパスします。

One Big Application Userモデルを使用するアプリケーションでは、データベースのセキュリティ・メカニズムを使用せずに、アプリケーション内にセキュリティ規定を作成する必要があります。ユーザーを認識するのは、データベースではなくアプリケーションであるため、アプリケーション自体が各ユーザーに対してセキュリティ対策を規定する必要があります。

このアプローチでは、データにアクセスする各アプリケーションでのセキュリティの再実装が必要になります。組織では複数のアプリケーションに同じセキュリティ・ポリシーを実装する必要があるため、セキュリティが高コストになり、新規アプリケーションごとに高コストな再実装が必要になります。

9.3 アプリケーション設計におけるパスワードの保護

Oracleでは、パスワード・サービスの安全な呼出し(スクリプトを使用するなど)のための戦略や、これらの戦略をその他の機密データに適用するための戦略を用意しています。

9.3.1 アプリケーションでのパスワードの保護に関する一般的なガイドライン

アプリケーションでのパスワードの保護に関するガイドラインでは、プラットフォーム固有のセキュリティ脅威などの領域を扱います。

9.3.1.1 プラットフォーム固有のセキュリティへの脅威

次の潜在的なセキュリティへの脅威は、わかりにくい可能性があるので注意してください。

これらのセキュリティへの脅威は次のとおりです。

  • UNIXおよびLinuxプラットフォームでは、同じホスト・コンピュータ上のすべてのオペレーティング・システム・ユーザーがコマンド・パラメータを表示できます。結果として、コマンドラインに入力したパスワードは他のユーザーに公開される可能性があります。ただし、UNIXおよびLinux以外のプラットフォームがこの脅威を回避できるとは考えないでください。

  • HP Tru64およびIBM AIXなど一部のUNIXプラットフォームでは、すべてのオペレーティング・システム・ユーザーがあらゆるプロセスの環境変数を表示できます。ただし、UNIXおよびLinux以外のプラットフォームがこの脅威を回避できるとは考えないでください。

  • Microsoft Windowsでは、コマンド・リコール機能(上矢印)に、コマンド起動間のユーザー入力が記憶されます。たとえば、SQL*PlusのCONNECT SYSTEM/password表記法を使用し、終了してから上矢印を押してCONNECTコマンドを繰り返した場合、コマンド・リコール機能により接続文字列が明らかになり、パスワードが表示されます。また、Microsoft Windows以外のプラットフォームがこの脅威を回避できるとは考えないでください。

9.3.1.2 パスワード入力を処理するアプリケーションの設計のガイドライン

Oracleには、パスワード入力を扱うアプリケーションの設計に関するガイドラインが用意されています。

  • パスワードの入力を対話形式で求めるアプリケーションを設計します。コマンドライン・ユーティリティの場合、コマンド・プロンプトでパスワードを公開することをユーザーに強制しないでください。

    アプリケーションの設計に使用するプログラミング言語のAPIについて、ユーザーからのパスワードを処理する最適な方法を確認します。この機能を処理するJavaコードの例は、「例: パスワードを読み取るためのJavaコード」を参照してください。

  • コード・インジェクション攻撃からデータベースを保護します。コード・インジェクション攻撃の標的は主に、データベースにSQLを送信するクライアント・アプリケーション・ツール(SQL*Plus、Oracle Call Interface (OCI)、JDBCアプリケーションなど)です。これらのツールを使用して作成されたデータベース・ドライバも含まれます。SQLインジェクション攻撃では、PL/SQLアプリケーションで想定されていない方法でSQL文が動作します。インジェクション攻撃は、データベースに文が送信される前に行われます。たとえば、侵入者はWHERE句をTRUEに設定してパスワード認証を回避できます。

    SQLインジェクション攻撃の問題に対処するには、バインド変数引数を使用するか妥当性チェックを作成します。バインド変数を使用できない場合は、DBMS_ASSERT PL/SQLパッケージを使用して入力値のプロパティを検証することを検討してください。DBMS_ASSERTパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。また、PUBLICなどのロールに対する権限付与も検討してください。

    インジェクションはデータベースに文が送信される前に行われる可能性があるため、クライアント・アプリケーションのユーザーがSQLインジェクションをPL/SQLに結び付けることができるとは限らないことに注意してください。

    SQLインジェクションの防止の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

  • 可能な場合は、認証を遅延するアプリケーションを設計します。たとえば:

    • ログインに証明書を使用します。

    • オペレーティング・システムで提供される機能を使用してユーザーを認証します。たとえば、Microsoft Windows上で動作するアプリケーションはドメイン認証を使用できます。

  • パスワードをマスクまたは暗号化します。パスワードを格納する必要がある場合、パスワードをマスクまたは暗号化します。たとえば、ログ・ファイルでパスワードをマスクし、リカバリ・ファイルでパスワードを暗号化できます。

  • 各接続を認証します。たとえば、スキーマAがデータベース1に存在する場合、データベース2のスキーマAが同一のユーザーであるとは考えないでください。同様に、ローカル・オペレーティング・システム・ユーザーpsmithは、必ずしもリモート・ユーザーpsmithと同じユーザーではありません。

  • ファイルまたはリポジトリにクリアテキスト・パスワードを格納しないでください。パスワードをファイルに格納すると、侵入者がパスワードにアクセスする危険性が高まります。

  • 1つのマスター・パスワードを使用します。たとえば:

9.3.1.3 パスワードの形式と動作の構成のガイドライン

Oracle Databaseには、パスワードの形式と動作の構成に関するガイドラインが用意されています。

9.3.1.4 SQLスクリプトにおけるパスワードの処理のガイドライン

Oracleには、SQLスクリプトにおけるパスワードの取扱いに関するガイドラインが用意されています。

  • プログラムまたはスクリプトのコマンドラインにパスワードを指定してSQL*Plusを起動しないでください。パスワードが必須であるにもかかわらず省略した場合、SQL*Plusではパスワードの入力を求めるプロンプトが表示され、パスワードが表示されないようにエコー機能が自動的に無効となります。

    次の各例は、パスワードがコマンドライン上で公開されないため安全です。また、Oracle Databaseではこれらのパスワードがネットワークを介して自動的に暗号化されます。

    $ sqlplus system
    Enter password: password
    
    SQL> CONNECT SYSTEM
    Enter password: password
    

    次の例では、パスワードが他のオペレーティング・システム・ユーザーに公開されます。

    sqlplus system/password
    

    次の例は、2つのセキュリティ上のリスクをもたらします。1つ目の例では、覗き込んでいる可能性のある他のユーザーにパスワードを公開してしまいます。2つ目の例では、Microsoft Windowsなどの一部のプラットフォームにおいて、パスワードがコマンドラインのリコール攻撃を受けやすくなります。

    $ sqlplus /nolog
    SQL> CONNECT SYSTEM/password
    
  • たとえばパスワードまたは秘密キーを必要とするSQLスクリプトの場合、アカウントを作成したりあるアカウントでログインするには、置換変数&1、&2などの位置パラメータを使用しないでください。かわりに、ユーザーに値の入力を求めるプロンプトを表示するスクリプトを設計します。また、スクリプトから、またはスプール・モードを使用している場合に出力を表示するエコー機能を無効にする必要があります。エコー機能を無効にするには、次の設定を使用します。

    SET ECHO OFF
    

    スクリプトにより値の目的を明白にする必要があります。たとえば、値によりアカウントまたは証明書などの新しい値が設定されるかどうか、または既存のアカウントへのログインなど、値が認証されるかどうかを明白にする必要があります。

    次の例は、セキュリティ上のリスクをもたらす方法でユーザーがスクリプトを起動することが回避されるため安全です。パスワードはエコーされず、スプール・ファイルに記録されません。

    SET VERIFY OFF
     ACCEPT user CHAR PROMPT ‘Enter user to connect to: ‘ 
     ACCEPT password CHAR PROMPT ‘Enter the password for that user: ' HIDE 
     CONNECT &user/&password 

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

    • SET VERIFY OFFは、パスワードの表示を防止します。(SET VERIFYは、置換の前後にスクリプトの各行をリストします。)SET VERIFY OFFコマンドをHIDEコマンドと結合する方法は、パスワードおよびその他の機密入力データを非表示にする便利なテクニックです。

    • ACCEPT password CHAR PROMPTは、ACCEPT passwordプロンプトにHIDEオプションを含めます。これによって入力パスワードのエコーが回避されます。

    次の例では位置パラメータを使用しており、ユーザーがコマンドライン上でパスワードを渡すことでスクリプトを起動できるため、セキュリティ上のリスクをもたらします。ユーザーがパスワードを入力せず、入力を求めるプロンプトが表示される場合、ユーザーが入力した内容がすべて画面およびスプール・ファイル(スプールが有効な場合)にエコーされるため危険です。

    CONNECT &1/&2
    
  • バッチ・スクリプトのログイン時間を制御します。パスワードを必要とするバッチ・スクリプトでは、実行されることになっている時間内のみにバッチ・スクリプトがログインできるようにアカウントを構成します。たとえば、毎日午後8時から1時間実行するバッチ・スクリプトを想定します。この時間のみスクリプトがログインできるようにアカウントを設定します。侵入者がアクセスしようとした場合、安全性の低いアカウントが利用される可能性は低くなります。

  • パスワードの入力を求めるDML文またはDDL SQL文を使用する場合は注意してください。この場合、機密情報がネットワークを介してクリアテキストで渡されます。Oracle厳密認証を使用して、この問題に対処できます。

    次のパスワード変更例は、パスワードが公開されないため安全です。

    password psmith
    Changing password for psmith
    New password: password
    Retype new password: password
    

    この例は、パスワードがコマンドラインおよびネットワーク上の両方に公開されるため、セキュリティ上のリスクをもたらします。

    ALTER USER psmith IDENTIFIED BY password 

9.3.2 外部パスワード・ストアを使用したパスワードの保護

データベースに接続するためのパスワード資格証明は、クライアント側のOracleウォレットを使用して格納できます。

Oracleウォレットは、ユーザーのログインに必要な認証および署名用証明書を格納する安全性の高いソフトウェア・コンテナです。

関連項目:

9.3.3 ORAPWDユーティリティを使用したパスワードの保護

SYSDBAまたはSYSOPERユーザーはパスワード・ファイルを使用して、ネットワーク経由でアプリケーションに接続できます。

  • パスワード・ファイルを作成するには、ORAPWDユーティリティを使用します。

関連項目:

パスワード・ファイルの作成および管理方法の詳細は、『Oracle Database管理者ガイド』を参照してください。

9.3.4 例: パスワードを読み取るためのJavaコード

パスワードの読取りに使用できるJavaパッケージを作成できます。

例9-1に、パスワードの読取りに使用できるJavaパッケージの作成方法を示します。

例9-1 パスワードを読み取るためのJavaコード

// Change the following line to a name for your version of this package
package passwords.sysman.emSDK.util.signing;

import java.io.IOException;
import java.io.PrintStream;
import java.io.PushbackInputStream;
import java.util.Arrays;
 
/**
 * The static readPassword method in this class issues a password prompt
 * on the console output and returns the char array password
 * entered by the user on the console input.
 */
public final class ReadPassword {
  //----------------------------------
  /**
   * Test driver for readPassword method.
   * @param args the command line args
   */
  public static void main(String[] args) {
    char[] pass = ReadPassword.readPassword("Enter password: ");
    System.out.println("The password just entered is \""
      + new String(pass) + "\"");
    System.out.println("The password length is " + pass.length);
  }
   * Issues a password prompt on the console output and returns
   * the char array password entered by the user on the console input.
   * The password is not displayed on the console (chars are not echoed).
   * As soon as the returned char array is not needed,
   * it should be erased for security reasons (Arrays.fill(charArr, ' '));
   * A password should never be stored as a java String.
   *
   * Note that Java 6 has a Console class with a readPassword method,
   * but there is no equivalent in Java 5 or Java 1.4.
   * The readPassword method here is based on Sun's suggestions at
   * http://java.sun.com/developer/technicalArticles/Security/pwordmask.
   *
   * @param prompt the password prompt to issue
   * @return new char array containing the password
   * @throws RuntimeException if some error occurs
   */
  public static final char[] readPassword(String prompt)
  throws RuntimeException {
    try {
      StreamMasker masker = new StreamMasker(System.out, prompt);
      Thread threadMasking = new Thread(masker);
      int firstByte = -1;
      PushbackInputStream inStream = null;
      try {
        threadMasking.start();
        inStream = new PushbackInputStream(System.in);
        firstByte = inStream.read();
      } finally {
        masker.stopMasking();
      }
      try {
        threadMasking.join();
      } catch (InterruptedException e) {
        throw new RuntimeException("Interrupt occurred when reading password");
      }
      if (firstByte == -1) {
        throw new RuntimeException("Console input ended unexpectedly");
      }
      if (System.out.checkError()) {
        throw new RuntimeException("Console password prompt output error");
      }
      inStream.unread(firstByte);
      return readLineSecure(inStream);
    }
    catch (IOException e) {
      throw new RuntimeException("I/O error occurred when reading password");
    }
  }
  //----------------------------------
  /**
   * Reads one line from an input stream into a char array in a secure way
   * suitable for reading a password.
   * The char array will never contain a '\n' or '\r'.
   *
   * @param inStream the pushback input stream
   * @return line as a char array, not including end-of-line-chars;
   *  never null, but may be zero length array
   * @throws RuntimeException if some error occurs
   */
  private static final char[] readLineSecure(PushbackInputStream inStream)
  throws RuntimeException {
    if (inStream == null) {
      throw new RuntimeException("readLineSecure inStream is null");
    }
    try {
      char[] buffer = null;
      try {
        buffer = new char[128];
        int offset = 0;
        // EOL is '\n' (unix), '\r\n' (windows), '\r' (mac)
        loop:
        while (true) {
          int c = inStream.read();
          switch (c) {
          case -1:
          case '\n':
            break loop;
          case '\r':
            int c2 = inStream.read();
            if ((c2 != '\n') && (c2 != -1))
              inStream.unread(c2);
            break loop;
          default:
            buffer = checkBuffer(buffer, offset);
            buffer[offset++] = (char) c;
            break;
          }
        }
        char[] result = new char[offset];
        System.arraycopy(buffer, 0, result, 0, offset);
        return result;
      }
      finally {
        if (buffer != null)
          Arrays.fill(buffer, ' ');
      }
    }
    catch (IOException e) {
      throw new RuntimeException("I/O error occurred when reading password");
    }
  }
  //----------------------------------
  /**
   * This is a helper method for readLineSecure.
   *
   * @param buffer the current char buffer
   * @param offset the current position in the buffer
   * @return the current buffer if it is not yet full;
   *  otherwise return a larger buffer initialized with a copy
   *  of the current buffer and then erase the current buffer
   * @throws RuntimeException if some error occurs
   */
  private static final char[] checkBuffer(char[] buffer, int offset)
  throws RuntimeException
  {
    if (buffer == null)
      throw new RuntimeException("checkBuffer buffer is null");
    if (offset < 0)
      throw new RuntimeException("checkBuffer offset is negative");
    if (offset < buffer.length)
      return buffer;
    else {
      try {
        char[] bufferNew = new char[offset + 128];
        System.arraycopy(buffer, 0, bufferNew, 0, buffer.length);
        return bufferNew;
      } finally {
        Arrays.fill(buffer, ' ');
      }
    }
  }
  //----------------------------------
  /**
   * This private class prints a one line prompt
   * and erases reply chars echoed to the console.
   */
  private static final class StreamMasker
  extends Thread {
    private static final String BLANKS = StreamMasker.repeatChars(' ', 10);
    private String m_promptOverwrite;
    private String m_setCursorToStart;
    private PrintStream m_out;
    private volatile boolean m_doMasking;
    //----------------------------------
    /**
     * Constructor.
     * @throws RuntimeException if some error occurs
     */
    public StreamMasker(PrintStream outPrint, String prompt)
    throws RuntimeException {
      if (outPrint == null)
        throw new RuntimeException("StreamMasker outPrint is null");
      if (prompt == null)
        throw new RuntimeException("StreamMasker prompt is null");
      if (prompt.indexOf('\r') != -1)
        throw new RuntimeException("StreamMasker prompt contains a CR");
      if (prompt.indexOf('\n') != -1)
        throw new RuntimeException("StreamMasker prompt contains a NL");
      m_out = outPrint;
      m_setCursorToStart = StreamMasker.repeatChars('\010',
        prompt.length() + BLANKS.length());
      m_promptOverwrite = m_setCursorToStart + prompt + BLANKS
        + m_setCursorToStart + prompt;
    }
    //----------------------------------
    /**
     * Begin masking until asked to stop.
     * @throws RuntimeException if some error occurs
     */
    public void run()
    throws RuntimeException {
      int priorityOriginal = Thread.currentThread().getPriority();
      Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
      try {
        m_doMasking = true;
        while (m_doMasking) {
          m_out.print(m_promptOverwrite);
          if (m_out.checkError())
            throw new RuntimeException("Console output error writing prompt");
          try {
            Thread.currentThread().sleep(1);
          } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
            return;
          }
        }
        m_out.print(m_setCursorToStart);
      } finally {
        Thread.currentThread().setPriority(priorityOriginal);
      }
    }
    //----------------------------------
    /**
     * Instructs the thread to stop masking.
     */
    public void stopMasking() {
      m_doMasking = false;
    }
    //----------------------------------
    /**
     * Returns a repeated char string.
     *
     * @param c the char to repeat
     * @param length the number of times to repeat the char
     * @throws RuntimeException if some error occurs
     */
    private static String repeatChars(char c, int length)
    throws RuntimeException {
      if (length < 0)
        throw new RuntimeException("repeatChars length is negative");
      StringBuffer sb = new StringBuffer(length);
      for (int i = 0; i < length; i++)
        sb.append(c);
      return sb.toString();
    }
  }
}

9.4 外部プロシージャの保護

外部プロシージャはデータベースとは別に.dllまたは.soファイルに保存され、資格証明認証で保護できます。

9.4.1 外部プロシージャの保護について

安全上の理由のため、Oracle外部プロシージャは、データベースと物理的に異なるプロセスで実行されます。

ほとんどの場合、このプロセスを構成して、Oracleソフトウェア・アカウント以外のユーザーとして実行します。アプリケーションがこの外部プロシージャを呼び出す場合(.dllまたは.soファイルのライブラリにアクセスする必要がある場合など)、Oracle Databaseがextprocと呼ばれるオペレーティング・システム・プロセスを作成します。デフォルトでは、extprocプロセスは、サーバー・プロセスで直接通信します。つまり、資格証明を使用しない場合、Oracle Databaseは、デフォルトのOracle Databaseサーバー構成でextprocプロセスを作成し、oracleソフトウェア・アカウントとしてextprocを実行します。また、Oracle Databaseリスナーを介して通信できます。

9.4.2 資格証明の認証に対するextprocの構成に関する一般プロセス

セキュリティを強化するために、extprocプロセスを構成して、資格証明を介して認証できます。

一般プロセスは次のとおりです。

  1. 資格証明を作成します。

    資格証明は、暗号化されたコンテナにあります。パブリック・シノニムとプライベート・シノニムの両方でこの資格証明を参照できます。「外部プロシージャの認証の構成」では、この資格証明を作成し、データベースを構成して使用する方法について説明します。

  2. 専用サーバーまたは共有サーバー・プロセスで実行しているデータベースへの最初の接続を行います。

  3. アプリケーションは、外部プロシージャへのコールを行います。

    これが最初のコールの場合、Oracle Databaseはextprocプロセスを作成します。extprocの資格証明を使用する場合、Oracleリスナーを使用してextprocプロセスを起動できません。

  4. extprocプロセスは、偽装(つまり、指定された資格証明のかわりに実行)して、必要な.dll.so.slまたは.aファイルをロードし、SQLおよびC間のデータを送信します。

9.4.3 extprocプロセス認証および偽装の予期される動作

extprocプロセスには、認証および偽装に対する一連の動作が含まれています。

表9-2では、可能性のある認証および偽装シナリオに基づくextprocプロセスの予期される動作について説明します。

表9-2 extprocプロセス認証および偽装設定の予期される動作

ENFORCE_CREDENTIAL環境変数設定 資格証明を使用したPL/SQLライブラリか GLOBAL_EXTPROC_CREDENTIAL資格証明の有無(1) 予期される動作

FALSE

いいえ

いいえ

OracleリスナーまたはOracleサーバー・プロセスの所有者のオペレーティング・システム権限で認証される12cより前のリリースの認証を使用します。

FALSE

いいえ

はい

Oracleインスタンス全体の指定されたGLOBAL_EXTPROC_CREDENTIALを使用して認証および偽装します(脚注2)

FALSE

はい

いいえ

PL/SQLライブラリで定義された資格証明を使用して認証および偽装します

FALSE

はい

はい

認証および偽装します(脚注3)

TRUE

いいえ

いいえ

エラーORA-28575: 外部プロシージャ・エージェントへのRPC接続をオープンできませんを戻します

TRUE

いいえ

はい

Oracleシステム全体の指定されたGLOBAL_EXTPROC_CREDENTIALを使用して認証および偽装します(脚注1)

TRUE

はい

いいえ

PL/SQLライブラリで定義された資格証明を使用して認証および偽装します

TRUE

はい

はい

認証および偽装します(脚注2)

脚注1 資格証明が明示的に指定されず、ENFORCE_CREDENTIAL環境変数がTRUEに設定されている場合、GLOBAL_EXTPROC_CREDENTIALは、デフォルトの資格証明の予約された資格証明名です。そのため、ENFORCE_CREDENTIALがTRUEに設定されている場合、この名前で資格証明を作成することをお薦めします。

脚注2

GLOBAL_EXTPROC_CREDENTIAL資格証明のみを使用している場合、このグローバル資格証明のEXECUTE権限が暗黙的にすべてのユーザーに自動的に付与されます。

脚注3

PL/SQLライブラリおよびGLOBAL_EXTPROC_CREDENTIAL設定の両方で資格証明が定義された場合、PL/SQLライブラリの資格証明が優先されます。

9.4.4 外部プロシージャの認証の構成

extprocプロセスの資格証明を構成するには、DBMS_CREDENTIAL PL/SQLパッケージを使用します。

  1. CREATE CREDENTIALまたはCREATE ANY CREDENTIAL権限が付与されたユーザーを使用してSQL*Plusにログインします。
    sqlplus psmith
    Enter password: password
    Connected.
    

    マルチテナント環境で、適切なプラガブル・データベース(PDB)に接続する必要があります。たとえば:

    sqlplus psmith@hpdb
    Enter password: password
    Connected.
    

    また、CREATE LIBRARYまたはCREATE ANY LIBRARY権限および外部コールを含むライブラリのEXECUTEオブジェクト権限があることも確認します。

  2. DBMS_CREDENTIAL PL/SQLパッケージを使用して、新しい資格証明を作成します。

    たとえば:

    BEGIN
      DBMS_CREDENTIAL.CREATE_CREDENTIAL (
        credential_name   => 'smith_credential', 
        user_name         => 'tjones',
        password          => 'password')
    END;
    /

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

    • credential_name: 資格証明の名前を入力します。オプションで、スキーマの名前(たとえば、psmith.smith_credentialなど)で接頭辞を付けます。ENFORCE_CREDENTIAL環境変数がTRUEに設定されている場合、credential_name GLOBAL_EXTPROC_CREDENTIALを使用して資格証明を作成する必要があります。

    • user_name: ユーザーとして実行するために使用する有効なオペレーティング・システム・ユーザー名を入力します。

    • password: user_nameユーザーに対するパスワードを入力します。

  3. 資格証明とPL/SQLライブラリを関連付けます。

    たとえば:

    CREATE OR REPLACE LIBRARY ps_lib  
     AS 'smith_lib.so' IN DLL_LOC
     CREDENTIAL smith_credential;
    

    この例では、DLL_LOCは、$ORACLE_HOME/binディレクトリを指すディレクトリ・オブジェクトです。DLLへの絶対パスの使用はお薦めしません。

    PL/SQLライブラリがextprocプロセスを介して外部プロシージャ・コールによってロードされる場合、extprocでは、定義されたsmith_credential資格証明のかわりに認証および偽装できます。

  4. 外部プロシージャのコール方法や渡す引数をPL/SQLに対して通知するPL/SQLプロシージャまたは関数を作成して、外部プロシージャを登録します。

    たとえば、Cで記述された外部プロシージャを登録する関数を作成するには、CREATE FUNCTION文のAS LANGUAGE CLIBRARYおよびNAME句のみ次のように使用します。

    CREATE OR REPLACE FUNCTION getInt (x VARCHAR2, y BINARY_INTEGER)
    RETURN BINARY_INTEGER
    AS LANGUAGE C
    LIBRARY ps_lib
    NAME "get_int_vals"
    PARAMETERS (x STRING, y int);

関連項目:

9.4.5 レガシー・アプリケーションの外部プロシージャ

セキュリティを最大にするために、ENFORCE_CREDENTIAL環境変数をTRUEに設定します。

ただし、下位互換性に対応する必要がある場合、ENFORCE_CREDENTIALFALSEに設定します。FALSEによって、extprocプロセスは、指定された資格証明のかわりにユーザー定義コールアウト関数を認証、偽装および実行できます。

  • 資格証明がPL/SQLライブラリで定義されます。

  • 資格証明は定義されていませんが、 GLOBAL_EXTPROC_CREDENTIAL資格証明が存在します。

これらの資格証明定義が設定されていない場合、ENFORCE_CREDENTIALパラメータをFALSEに設定すると、OracleリスナーまたはOracleサーバー・プロセスの所有者のオペレーティング・システム権限で認証されるextprocプロセスが設定されます。

extprocプロセス上で実行されるレガシー・アプリケーションでは、レガシー・アプリケーション・コードを変更して、すべての別名ライブラリと資格証明を関連付けることをお薦めします。これを実行できない場合、Oracle DatabaseはGLOBAL_EXTPROC_CREDENTIAL資格証明を使用して、認証の処理方法を決定します。GLOBAL_EXTPROC_CREDENTIAL資格証明が定義されていない場合、extprocプロセスは、OracleリスナーまたはOracleサーバー・プロセスの所有者のオペレーティング・システム権限で認証されます。

9.5 アプリケーション権限の管理

ほとんどのデータベース・アプリケーションでは、異なるスキーマ・オブジェクトごとに異なる権限が関与します。

各アプリケーションに必要な権限の追跡は、複雑な場合があります。また、アプリケーションを実行するユーザーの認可には、多くのGRANT操作が関与する場合があります。

  • アプリケーションの権限管理を簡素化するために、アプリケーションごとに作成した1つのロールに、1人のユーザーがそのアプリケーションを実行するために必要なすべての権限を付与します。

    実際には、1つのアプリケーションに複数のロールがある可能性があり、各ロールには、アプリケーションの実行中に使用できる機能の多少を決める権限の特定サブセットが付与されます。

たとえば、すべての管理アシスタントが休暇アプリケーションを使用して、部門のメンバーが取得した休暇を記録するとします。このアプリケーションを効率的に管理するには、次の操作手順が必要です。

  1. VACATIONロールを作成します。
  2. 休暇アプリケーションに必要なすべての権限をVACATIONロールに付与します。
  3. VACATIONロールをすべての管理アシスタントに付与します。より効率的な方法は、管理アシスタントが持つ権限を定義したロールを作成し、VACATIONロールをそのロールに付与します。

関連項目:

9.6 アプリケーション権限の管理にロールを使用する利点

複数のアプリケーション権限を1つのロールにグループ化すると、権限の管理に役立ちます。

次の管理オプションを考えてみます。

  • アプリケーションを実行するユーザーに、多数の個別の権限ではなく、ロールを付与できます。したがって、従業員が業務を変更するときは、多くの権限ではなく、1つのロールのみを付与または取り消す必要があります。

  • アプリケーションに対応付けられている権限の変更は、そのアプリケーションのすべてのユーザーが保持する権限ではなく、ロールに付与されている権限のみを修正することで実行できます。

  • 特定のアプリケーションの実行に必要な権限は、ROLE_TAB_PRIVSROLE_SYS_PRIVSの各データ・ディクショナリ・ビューを問い合せることで判断できます。

  • どのユーザーに、どのアプリケーションの権限があるかは、DBA_ROLE_PRIVSデータ・ディクショナリ・ビューを問い合せることで判断できます。

9.7 アプリケーションへのアクセスを制御するセキュア・アプリケーション・ロールの作成

セキュア・アプリケーション・ロールは関連するPL/SQLパッケージまたはプロシージャでのみ使用可能にできます。

9.7.1 ステップ1: セキュア・アプリケーション・ロールの作成

IDENTIFIED USING句を持つCREATE ROLE文で、セキュア・アプリケーション・ロールを作成します。

この文を実行するには、CREATE ROLEシステム権限が必要です。

たとえば、sec_mgr.hr_adminパッケージに対応付けられるhr_adminというセキュア・アプリケーション・ロールを作成するには、次の手順を実行します。

  1. 次のようにセキュア・アプリケーション・ロールを作成します。
    CREATE ROLE hr_admin IDENTIFIED USING sec_mgr.hr_admin_role_check;
    

    この例から次のようなことがわかります。

  2. セキュア・アプリケーション・ロールに対して、このロールに通常対応付ける権限を付与します。

    たとえば、HR.EMPLOYEES表に対するSELECTINSERTUPDATEおよびDELETE権限をhr_adminロールに付与するには、次の文を入力します。

    GRANT SELECT, INSERT, UPDATE, DELETE ON HR.EMPLOYEES TO hr_admin;
    

    このロールをユーザーに直接付与しないでください。ユーザーがセキュリティ・ポリシーを通過した場合は、PL/SQLプロシージャまたはパッケージによってこのロールが自動的に付与されます。

9.7.2 ステップ2: アプリケーションに対するアクセス・ポリシーを定義するPL/SQLパッケージの作成

アプリケーションに対するアクセス・ポリシーを定義するPL/SQLパッケージを作成できます。

9.7.2.1 アプリケーションに対するアクセス・ポリシーを定義するPL/SQLパッケージの作成について

セキュア・アプリケーション・ロールを有効または無効にするには、PL/SQLパッケージ内にロールのセキュリティ・ポリシーを作成する必要があります。

個別のプロシージャを作成してこれを実行することもできますが、パッケージを使用すると、一連のプロシージャをグループ化できます。これにより、一緒に使用するポリシーのグループを作成して、アプリケーションを保護するための強固なセキュリティ戦略を提示できます。セキュリティ・ポリシーに失敗したユーザー(潜在的な侵入者)については、監査チェックをパッケージに追加して、その失敗を記録できます。通常、このパッケージは、セキュリティ管理者のスキーマに作成します。

このパッケージまたはプロシージャは、次の内容を実行する必要があります。

  • 実行者権限を使用してロールを有効にする必要があります。実行者権限を使用してパッケージを作成するには、AUTHIDプロパティをCURRENT_USERに設定する必要があります。定義者権限を使用してパッケージを作成することはできません。

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

  • ユーザーを検証するためのセキュリティ・チェックを1つ以上組み込む必要があります。ユーザーを検証する方法の1つは、SYS_CONTEXT SQLファンクションを使用することです。SYS_CONTEXTの詳細は、Oracle Database SQL言語リファレンスを参照してください。ユーザーに関するセッション情報を検索するために、アプリケーション・コンテキストでSYS_CONTEXTを使用できます。詳細は、「アプリケーション・コンテキストを使用したユーザー情報の取得」を参照してください。

  • ユーザーがセキュリティ・チェックを通過するときにSET ROLE SQL文またはDBMS_SESSION.SET_ROLEプロシージャを発行する必要があります。パッケージは実行者権限を使用して作成するため、SET ROLE SQL文またはDBMS_SESSION.SET_ROLEプロシージャを発行することによりロールを設定する必要があります。(ただし、このタイプのロール有効化でSET ROLE ALL文を使用することはできません。)PL/SQL埋込みSQL構文はSET ROLE文をサポートしませんが、動的SQL(たとえばEXECUTE IMMEDIATEにより)を使用することによりSET ROLEを起動できます。

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

このパッケージまたはプロシージャの作成方法が原因で、セキュア・アプリケーション・ロールを使用可能または使用禁止にする際にログイン・トリガーを使用できません。かわりに、ユーザーがセキュリティ・アプリケーション・ロールで付与された権限を使用する前のユーザー・ログイン時に、アプリケーションからパッケージを直接起動します。

9.7.2.2 アプリケーションに対するアクセス・ポリシーを定義するPL/SQLパッケージまたはプロシージャの作成

作成するPL/SQLパッケージまたはプロシージャでは、アクセス・ポリシーを定義するために実行者権限を使用する必要があります。

たとえば、hr_adminロールを使用する全員を、オンサイト(特定の端末を使用)で午前8時から午後5時まで勤務する従業員に限定するとします。システム管理者またはセキュリティ管理者として、アプリケーションに対してアクセス・ポリシーを定義するプロシージャを作成できます。

  1. 次のようにプロシージャを作成します。
    CREATE OR REPLACE PROCEDURE hr_admin_role_check
     AUTHID CURRENT_USER 
     AS 
     BEGIN 
      IF (SYS_CONTEXT ('userenv','ip_address') 
        IN ('192.0.2.10' , '192.0.2.11')
         AND
        TO_CHAR (SYSDATE, 'HH24') BETWEEN 8 AND 17)
      THEN
        EXECUTE IMMEDIATE 'SET ROLE hr_admin'; 
      END IF;
     END;
    /

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

    • AUTHID CURRENT_USERは、実行者権限を使用できるように、AUTHIDプロパティをCURRENT_USERに設定します。

    • IF (SYS_CONTEXT ('userenv','ip_address')は、ユーザー・セッション情報を取得するSYS_CONTEXT SQLファンクションを使用してユーザーを検証します。

    • BETWEEN ... TO_CHARは、アクセス権を付与または拒否するテストを作成します。テストはオンサイト(つまり、特定の端末を使用中)で午前8:00から午後5:00までの時間に作業するユーザーについて、アクセスを制限します。ユーザーがこのチェックを通過すると、hr_adminロールが付与されます。

    • THEN... EXECUTEは、ユーザーがこのテストを通過した場合は、EXECUTE IMMEDIATEコマンドを使用してSET ROLE文を発行し、そのユーザーにロールを付与します。

  2. ロールが割り当てられたユーザーに対して、hr_admin_role_checkプロシージャのEXECUTE権限を付与します。

    たとえば:

    GRANT EXECUTE ON hr_admin_role_check TO psmith;
9.7.2.3 セキュア・アプリケーション・ロールのテスト

セキュア・アプリケーション・ロールを付与されたユーザーとして、そのロールで付与される権限を要するアクションを実行します。

セキュア・アプリケーション・ロールを付与されたユーザーとしてログインすると、そのロールが有効になります。

  1. そのユーザーとしてデータベース・セッションにログインします。

    たとえば:

    CONNECT PSMITH@hrpdb
    Enter password: password
    
  2. セキュア・アプリケーション・ロールで付与される権限を要求するアクションを実行します。

    たとえば、そのロールがsec_admin.hr_admin_role_checkプロシージャに対してEXECUTE権限を付与するとします。

    EXECUTE sec_admin.hr_admin_role_check;
    

9.8 権限とユーザーのデータベース・ロールとの関連付け

ユーザーの権限が、現在のデータベース・ロールに関連した権限のみであることを確認します。

9.8.1 ユーザーの権限が現在のデータベース・ロールのみである理由

1人のユーザーが、多数のアプリケーションおよび多数の対応付けられたロールを使用できます。

ただし、このユーザーの権限は、現在のデータベース・ロールに関連した権限のみであることを確認する必要があります。

次の使用例を考えてみます。

  • (「受注」というアプリケーションの)ORDERロールには、INVENTORY表に対するUPDATE権限が含まれています。

  • (「在庫」というアプリケーションの)INVENTORYロールには、INVENTORY表に対するSELECT権限が含まれています。

  • 何人かの受注入力担当には、ORDERロールとINVENTORYロールの両方が付与されています。

このシナリオでは、両方のロールを付与された受注入力担当がINVENTORYアプリケーションの実行時にORDERロールの権限を使用してINVENTORY表を更新できます。問題は、INVENTORY表の更新は、INVENTORYアプリケーションにとって承認された操作ではないということです。ORDERアプリケーションにとって承認された操作です。この問題を防ぐには、SET ROLE文を次のセクションの説明のとおりに使用します。

9.8.2 ロールを自動的に使用可能または使用禁止にするSET ROLE文の使用

各アプリケーションの開始時にSET ROLE文を使用して、各アプリケーションに対応付けられているロールを自動的に使用可能にし、他のすべてのロールを使用禁止にします。

この方法によって、各アプリケーションでは、必要な場合にのみ、ユーザーの特定の権限を動的に使用可能にします。SET ROLE文は、権限の管理を簡素化します。ユーザーがどのような情報にアクセスできるかと、その情報にいつアクセスできるかを制御します。また、このSET ROLE文によって、ユーザーは、明確に定義された権限ドメイン内で操作を続行できます。あるユーザーがロールからのみ権限を取得している場合、そのユーザーはこれらの権限を組み合せて不正な操作を実行することはできません。

9.9 スキーマを使用したデータベース・オブジェクトの保護

スキーマとは、データベース・オブジェクトを含めることができるセキュリティ・ドメインです。ユーザーおよびロールに付与された権限によって、これらのデータベース・オブジェクトへのアクセスが制御されます。

9.9.1 一意スキーマでのデータベース・オブジェクトの保護

ほとんどのスキーマはユーザー名と考えることができます。つまり、ユーザーがデータベースに接続してそのデータベース・オブジェクトへのアクセスを可能にするアカウントです。

ただし、一意スキーマではデータベースへの接続は許可されませんが、関連する一連のオブジェクトを格納するために使用されます。この種のスキーマは通常ユーザーとして作成されますが、CREATE SESSIONシステム権限は(明示的にもロールを介しても)付与されません。

  • オブジェクトを保護するには、CREATE SCHEMAを使用して、1つのトランザクション内に複数の表とビューを作成する場合は、一意スキーマにCREATE SESSIONおよびRESOURCE権限を一時的に付与します。

たとえば、所定のスキーマが特定のアプリケーションのスキーマ・オブジェクトを所有する場合があります。アプリケーション・ユーザーに権限がある場合、そのユーザーは、一般的なデータベース・ユーザー名を使用してデータベースに接続し、アプリケーションとそれに対応するオブジェクトを使用できます。ただし、ユーザーはアプリケーションに設定されたスキーマを使用して、データベースに接続することはできません。この構成は、対応付けられたオブジェクトへのスキーマを介したアクセスを防ぎ、スキーマ・オブジェクトの保護を強化します。この場合、アプリケーションではALTER SESSION SET CURRENT_SCHEMA文を発行して、ユーザーを適切なアプリケーション・スキーマに接続できます。

9.9.2 共有スキーマでのデータベース・オブジェクトの保護

多くのアプリケーションでは、ユーザーがアクセスする必要があるのはアプリケーション・スキーマのみであるため、データベースで自分自身のアカウントつまりスキーマを必要としません。

たとえば、ユーザーJohn、FiruzehおよびJaneはすべて給与アプリケーションのユーザーで、financeデータベースのpayrollスキーマにアクセスする必要があるとします。この場合、データベースに自分自身のオブジェクトを作成する必要があるユーザーはいません。これらのユーザーに必要なのは、payrollオブジェクトへのアクセスのみです。この問題に対処するために、Oracle Databaseではエンタープライズ・ユーザー(スキーマに依存しないユーザー)が提供されています。

エンタープライズ・ユーザー、つまりディレクトリ・サービスで管理されるユーザーは、共有データベース・スキーマを使用するため、データベース・ユーザーとして作成する必要はありません。管理コストを削減するために、管理者はディレクトリに1つのエンタープライズ・ユーザーを1回作成し、他の多数のユーザーもアクセスできる共有スキーマで、そのユーザーを指し示すことができます。

関連項目:

エンタープライズ・ユーザーの管理の詳細は、『Oracle Databaseエンタープライズ・ユーザー・セキュリティ管理者ガイド』を参照してください。

9.10 アプリケーションでのオブジェクト権限

アプリケーションの設計時には、ユーザーのタイプとユーザーに必要なレベル・アクセスについて検討する必要があります。

9.10.1 アプリケーション開発者に必要なオブジェクト権限に関する知識

オブジェクト権限によって、エンド・ユーザーは、表、ビュー、順序、プロシージャ、ファンクション、パッケージなどのオブジェクトに対してアクションを実行できます。

表9-3に、オブジェクトの各タイプで使用できるオブジェクト権限の概要を示します。

表9-3 権限とスキーマ・オブジェクトとの関連

オブジェクト権限 表への適用 ビューへの適用 順序への適用 プロシージャへの適用(4)

ALTER

はい

いいえ

はい

いいえ

DELETE

はい

はい

いいえ

いいえ

EXECUTE

いいえ

いいえ

いいえ

はい

INDEX

はい脚注 5

いいえ

いいえ

いいえ

INSERT

はい

はい

いいえ

いいえ

REFERENCES

はいはい(5)

いいえ

いいえ

いいえ

SELECT

はい

はい脚注6

はい

いいえ

UPDATE

はい

はい

いいえ

いいえ

脚注4 スタンドアロンのストアド・プロシージャ、関数およびパブリック・パッケージ構成

脚注5

ロールに付与できない権限

脚注6

スナップショットに対しても付与可能

9.10.2 オブジェクト権限によって許可されるSQL文

アプリケーションの実装時およびテスト時には、必要な各ロールを作成する必要があります。

各ロールの使用例をテストし、データベースへのアクセス権がアプリケーション・ユーザーに正しく付与されることを確認します。テスト終了後は、アプリケーションの管理者と共同で各ユーザーに適切なロールが割り当てられていることを確認します。

表9-4に、表9-3で示したオブジェクト権限によって許可されるSQL文を示します。

表9-4 データベース・オブジェクト権限によって許可されるSQL文

オブジェクト権限 許可されるSQL文

ALTER

ALTERオブジェクト(表または順序)

CREATE TRIGGER ONオブジェクト(表のみ)

DELETE

DELETE FROMオブジェクト(表、ビューまたはシノニム)

EXECUTE

EXECUTEオブジェクト(プロシージャまたはファンクション)

パブリック・パッケージ変数への参照

INDEX

CREATE INDEX ONオブジェクト(表、ビューまたはシノニム)

INSERT

INSERT INTOオブジェクト(表、ビューまたはシノニム)

REFERENCES

オブジェクト(表のみ)に対するFOREIGN KEY整合性制約を定義するCREATEまたはALTER TABLE

SELECT

SELECT...FROMオブジェクト(表、ビュー、シノニムまたはスナップショット)

順序を使用するSQL文

9.11 データベース通信のセキュリティを強化するためのパラメータ

プロトコル・エラーによる不正パケットの処理や認証エラーの上限の構成など、パラメータを使用してセキュリティを管理できます。

9.11.1 プロトコル・エラーによってデータベースで受信した不正パケット

SEC_PROTOCOL_ERROR_TRACE_ACTION初期化パラメータで、プロトコル・エラーが発生したときにトレース・ファイルをどのように管理するかを制御します。

サーバーが不正なパケット、順序に誤りがあるパケット、プライベートまたは未使用のリモート・プロシージャ・コールを受信した場合、Oracle Call Interface(OCI)やTwo-Task Common(TTC)などのネットワーキング通信ユーティリティでは、スタック・トレースおよびヒープ・ダンプを格納する大規模なディスク・ファイルを生成できます。

通常、このディスク・ファイルは、非常に大規模になる可能性があります。侵入者は、サーバーに不正なパケットを繰り返し送信し、ディスクあふれやサービス拒否(DOS)攻撃を発生させることで、システムを使用できないようにする可能性があります。認証されていないクライアントが、この種の攻撃を仕掛ける可能性もあります。

これらの攻撃は、SEC_PROTOCOL_ERROR_TRACE_ACTION初期化パラメータを次の値のいずれかに設定することで防止できます。

  • None: サーバーが不正なパケットを無視し、トレース・ファイルまたはログ・メッセージを生成しないように構成します。サーバーの可用性が不正なパケットの受信を認識することよりも圧倒的に重要な場合は、この設定を使用します。

    たとえば:

    SEC_PROTOCOL_ERROR_TRACE_ACTION = None
    
  • Trace(デフォルト設定): トレース・ファイルを作成します。これは、ネットワーク・クライアントが不具合の結果として不正なパケットを送信している場合など、デバッグを目的とする場合に便利です。

    たとえば:

    SEC_PROTOCOL_ERROR_TRACE_ACTION = Trace
    
  • Log: サーバー・トレース・ファイルに1行の短いメッセージを書き込みます。この選択肢では、一定レベルの監査とシステムの可用性とのバランスがとれます。

    たとえば:

    SEC_PROTOCOL_ERROR_TRACE_ACTION = Log
    
  • Alert: データベース管理者または監視コンソールにアラート・メッセージを送信します。

    たとえば:

    SEC_PROTOCOL_ERROR_TRACE_ACTION = Alert

9.11.2 不正パケット受信後のサーバー実行の制御

SEC_PROTOCOL_ERROR_FURTHER_ACTION初期化パラメータで、サーバーで不正パケットを受信した後のサーバー実行を制御します。

Oracle Databaseは、クライアントまたはサーバー・プロトコルからエラーを検出した後も実行を継続する必要があります。ただし、これによって、ディスクあふれまたはサービス拒否攻撃を発生させる可能性のある不正なパケットを、サーバーがさらに受信する可能性があります。
  • サーバーが悪意のあるクライアントから不正なパケットを受信しているときに、サーバー・プロセスの実行を詳細に制御するには、SEC_PROTOCOL_ERROR_FURTHER_ACTION初期化パラメータを次の値のいずれかに設定します。

    • Continue: サーバーの実行を続行します。ただし、サーバーがさらに攻撃を受ける可能性があることに注意してください。

      たとえば:

      SEC_PROTOCOL_ERROR_FURTHER_ACTION = Continue
      
    • (Delay,m): クライアントをm秒間遅延させます(サーバーが次のリクエストを同じクライアント接続から受け付けるまで)。この設定により悪意のあるクライアントはサーバー・リソースを過剰使用できなくなります。正当なクライアントのパフォーマンスも低下しますが、引き続き機能します。この設定を入力する場合は、カッコで囲みます。

      たとえば:

      SEC_PROTOCOL_ERROR_FURTHER_ACTION = (Delay,3)

      ALTER SYSTEMまたはALTER SESSION SQL文を使用してSEC_PROTOCOL_ERROR_FURTHER_ACTIONを設定している場合は、Delay設定を一重引用符または二重引用符で囲む必要があります。

      ALTER SYSTEM SEC_PROTOCOL_ERROR_FURTHER_ACTION = '(Delay,3)';
    • (Drop,n): クライアント接続は、n個の不正パケットを受信した後に強制的に終了します。この設定を使用すると、トランザクションの損失など、クライアントを犠牲にしてサーバー自体を保護できます。ただし、クライアントは再度接続して、同じ操作を再試行できます。この設定はカッコで囲みます。SEC_PROTOCOL_ERROR_FURTHER_ACTIONのデフォルト値は、(Drop,3)です。

      たとえば:

      SEC_PROTOCOL_ERROR_FURTHER_ACTION = (Drop,10)

      Delay設定と同様に、ALTER SYSTEMまたはALTER SESSIONを使用してこの設定を変更している場合は、Drop設定を一重引用符または二重引用符で囲む必要があります。

9.11.3 認証の最大試行回数の構成

SEC_MAX_FAILED_LOGIN_ATTEMPTS初期化パラメータに設定された認証試行回数を超過すると、確立できなかった接続がデータベースで削除されます。

接続作成の一環として、リスナーはサーバー・プロセスを開始し、そのプロセスをクライアントに付加します。この物理的な接続を使用して、クライアントは接続を認証できます。サーバー・プロセスが開始された後、このサーバー・プロセスに対してクライアントが認証がされます。侵入者は、サーバー・プロセスを起動し、様々なユーザー名とパスワードを使用して認証リクエストを無制限に発行し、データベースへのアクセスを試みます。

アプリケーション接続に対するログイン失敗回数を制限するには、SEC_MAX_FAILED_LOGIN_ATTEMPTS初期化パラメータを設定して、接続に対する認証試行回数を制限します。認証の試行が指定した回数失敗すると、データベース・プロセスは接続を切断し、サーバー・プロセスが終了します。デフォルトでは、SEC_MAX_FAILED_LOGIN_ATTEMPTS3に設定されます。

SEC_MAX_FAILED_LOGIN_ATTEMPTS初期化パラメータは、潜在的な侵入者によるアプリケーションへの攻撃を防ぐために設計されているだけでなく、パスワードを忘れた正当なユーザーも対象となることに留意してください。sqlnet.ora INBOUND_CONNECT_TIMEOUTパラメータとFAILED_LOGIN_ATTEMPTSプロファイル・パラメータもログイン失敗を制限しますが、この2つのパラメータは正当なユーザー・アカウントにのみ適用されるという点で異なります。

たとえば、最大試行回数を5に制限するには、initsid.ora初期化パラメータ・ファイルで、次のようにSEC_MAX_FAILED_LOGIN_ATTEMPTSを設定します。

SEC_MAX_FAILED_LOGIN_ATTEMPTS = 5

9.11.4 データベース・バージョン・バナーの表示構成

SEC_RETURN_SERVER_RELEASE_BANNER初期化パラメータを使用して、認証中の詳細な製品情報の表示を抑制できます。

クライアント接続(Oracle Call Interfaceクライアントを含む)が認証されてから、詳細な製品バージョン情報にアクセスできるようにする必要があります。侵入者は、データベース・バージョンを使用して、データベース・ソフトウェアに存在するセキュリティの脆弱性に関する情報を検出する可能性があります。

  • 認証されていないクライアントに対してデータベース・バージョン・バナーの表示を制限するには、initsid.ora初期化パラメータ・ファイルでSEC_RETURN_SERVER_RELEASE_BANNER初期化パラメータをTRUEまたはFALSEのいずれかに設定します。

    デフォルトでは、SEC_RETURN_SERVER_RELEASE_BANNERFALSEに設定されます。

たとえば、TRUEに設定すると、Oracle Databaseに正確なデータベース・バージョンが表示されます。たとえば、リリース12.2.0.0の場合は次のようになります。

Oracle Database 12c Enterprise Edition Release 12.2.0.0 - Production

リリース番号にポイント・リリース表記法(Oracle Databaseリリース12.2.0.1など)が使用されている場合、バナーには次のように表示されます。

Oracle Database 12c Enterprise Edition Release 12.2.0.1 - Production

ただし、同じリリースでこのパラメータをNOに設定すると、このバナーは制限されて、リリース12.2で始まる次の固定テキスト(12.2.0.1のかわりに12.2.0.0.0)が表示されます。

Oracle Database 12c Release 12.2.0.0.0 - Production

9.11.5 不正なアクセスおよびユーザー・アクションの監査に関するバナーの構成

SEC_USER_UNAUTHORIZED_ACCESS_BANNERおよびSEC_USER_AUDIT_ACTION_BANNER初期化パラメータで、不正アクセスやユーザーの監査に関するバナーの表示を制御します。

不正なアクセスおよびユーザー・アクション監査をユーザーに警告するには、バナーを作成して構成する必要があります。この通知は、クライアント・アプリケーションがデータベースにログインすると使用可能になります。

  • これらのバナーを構成して表示するには、データベース・サーバー側で次のsqlnet.oraパラメータを設定して、バナー情報が含まれるテキスト・ファイルを指し示します。

    • SEC_USER_UNAUTHORIZED_ACCESS_BANNER。たとえば:

      SEC_USER_UNAUTHORIZED_ACCESS_BANNER = /opt/Oracle/12c/dbs/unauthaccess.txt
      
    • SEC_USER_AUDIT_ACTION_BANNER。たとえば:

      SEC_USER_AUDIT_ACTION_BANNER = /opt/Oracle/12c/dbs/auditactions.txt
      

デフォルトでは、これらのパラメータは設定されません。さらに、バナー・テキストに使用される文字数には512バイトの制限があることを注意してください。

これらのパラメータを設定したら、これらのバナーを取得してエンドユーザーに表示するように、Oracle Call Interfaceアプリケーションで適切なOCI APIを使用する必要があります。