9 MLEのセキュリティ

MLEは、適切なセキュリティ・プラクティスをサポートするために様々な方法を利用しています。これには、ランタイム状態の分離、システム権限およびオブジェクト権限の強制や、モニタリング・オプションの提供が含まれます。

トピック

MLEでのJavaScriptの操作に必要なシステム権限およびオブジェクト権限

プロジェクトの要件に応じて、データベース内のJavaScriptと対話できるように、様々な権限をユーザーおよびロールに付与できます。

管理者は、アプリケーションの要件を慎重に確認し、ユーザーに必要な最小数の権限のみを付与する必要があります。このことは特にシステム権限に当てはまり、これは非常に強力であるため、信頼できるユーザーにのみ付与する必要があります。

MLE JavaScriptコードを操作するために必要な最小権限は、データベースでJavaScriptコードを実行する権限です。MLEは、DBMS_MLEに基づいた動的MLE実行と、MLEモジュールおよび環境を使用したMLE実行を区別します。

JavaScriptにストアド・コードを作成するには、独自のスキーマにJavaScriptスキーマ・オブジェクトを作成するための追加の権限が必要です。

MLEで使用可能な最も強力な権限では、スーパーユーザーは自分のスキーマのみでなく、任意のスキーマにMLEスキーマ・オブジェクトを作成、変更および削除できます。Oracle Databaseのすべての権限と同様に、名前にANYが含まれている権限が最も強力であるため、絶対に必要であるとされた場合にのみ、信頼できるユーザーに付与する必要があります。

ノート:

モジュールおよび環境に対するオブジェクト権限では、コール仕様(またはDBMS_MLE)によって定義されたソース・コードとユーザー・コンテキストの組合せなど、アプリケーションへのアクセス権は付与されません。これは、コール仕様のプロシージャまたはファンクション・オブジェクトへのアクセス権を付与することで実現されます。

関連項目:

トピック

JavaScriptコードの実行に必要な権限

独自のスキーマでJavaScriptコードを実行する前に、次のオブジェクト権限付与がユーザー・アカウントに発行されている必要があります:

GRANT EXECUTE ON JAVASCRIPT TO <role | user>

EXECUTE ON JAVASCRIPT権限には、DBMS_MLEを使用したJavaScriptの動的実行は含まれません。DBMS_MLEを使用する場合は、追加の権限が必要です:

GRANT EXECUTE DYNAMIC MLE TO <role | user>

NoSQL APIを使用するために必要な権限

MLE JavaScriptコードがSimple Oracle Document Access (SODA)を参照する場合、SODA_APPロールをユーザーまたはロールに付与する必要があります:

GRANT SODA_APP <role | user>

MLEスキーマ・オブジェクトを作成するために必要な権限

独自のスキーマでMLEモジュールおよび環境を作成する場合は、さらにシステム権限が必要です:

GRANT CREATE MLE TO <role | user>

MLEモジュールがコール仕様の形式でデータベースのSQLレイヤーおよびPL/SQLレイヤーに公開される場合は、PL/SQLプロシージャを作成する権限も必要です:

GRANT CREATE PROCEDURE TO <role | user>

多くの場合、ユースケースに応じて、表、索引、順序などの追加のスキーマ・オブジェクトを作成するために、さらにシステム権限が必要になります。Oracle Database 23c以降、DB_DEVELOPER_ROLEロールを使用すると、次のスニペットに示すように、管理者はローカル開発データベースの開発者に必要な権限をすばやく付与できます:

BEGIN
    DBMS_DEVELOPER_ADMIN.GRANT_PRIVS('DEVUSER');
END;
/

関連項目:

DB_DEVELOPER_ROLEロールの詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください

任意のスキーマでMLEモジュールおよび環境を作成するために必要な権限

パワー・ユーザーおよび管理者に追加の権限を付与して、任意のスキーマでMLEスキーマ・オブジェクトを作成、変更および削除できるようにすることができます。

GRANT CREATE ANY MLE TO <role | user>
GRANT DROP ANY MLE TO <role | user>
GRANT ALTER ANY MLE TO <role | user>

名前にANYを含むOracle Databaseのすべての権限と同様に、これらは非常に強力であるため、徹底的に調査した後に信頼できるユーザーにのみ付与する必要があります。このため、DBAロールおよびSYSアカウントにのみこれらの権限が付与されています。これらのシステム権限の使用は、ORA_SECURECONFIG監査ポリシーによって監査されます。

独自のスキーマ以外のスキーマでMLEコール仕様を作成するには、CREATE ANY PROCEDUREに対する権限も付与する必要があります:

GRANT CREATE ANY PROCEDURE TO <role | user>

前に示したシステム権限と同様に、CREATE ANY PROCEDUREは、同じ監査ポリシーORA_SECURECONFIGによって監査されます。

関連項目:

ORA_SECURECONFIG監査ポリシーの詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください

実行後デバッグに必要な権限

他のデータベース・ユーザーは、所有していないMLEモジュールのデバッグ情報を収集できます。デフォルトでは、MLE所有者は、特定の権限なしで独自のMLEモジュールで実行後デバッグを使用できます。デバッグ情報を収集する権限を別のロールまたはユーザーに付与して、モジュール所有者の代理としてJavaScriptコードの実行後デバッグを使用できるようにすることが可能です:

GRANT COLLECT DEBUG INFO ON <module> TO <role | user>

ノート:

PL/SQLコードとして作成されたMLEモジュール・コールに対する実行権限を、定義者権限を持つ他のスキーマのユーザーに付与することもできます。この場合、他のユーザーに追加の権限を付与する必要はありません。

ノート:

モジュールおよび環境に対するオブジェクト権限では、コール仕様(またはDBMS_MLE)によって定義されたソース・コードとユーザー・コンテキストの組合せなど、アプリケーションへのアクセス権は付与されません。これは、コール仕様のプロシージャまたはファンクション・オブジェクトへのアクセス権を付与することで実現されます。

関連項目:

実行後デバッグの詳細は、「MLE JavaScriptモジュールの実行後デバッグ」を参照してください

MLEのセキュリティに関する考慮事項

アカウント権限の使用に加えて、MLEは他のいくつかの方法を使用して、高レベルのセキュリティを確保します。

トピック

初期化パラメータ

新しい初期化パラメータMLE_PROG_LANGUAGESを使用すると、管理者はマルチリンガル・エンジンを完全に有効または無効にしたり、特定の言語を選択的に有効にしたりできます。これは、値ALLJAVASCRIPTまたはOFFを使用し、複数のレベルで設定できます:

  • コンテナ・データベース(CDB)

  • プラガブル・データベース(PDB)

  • データベース・セッション

このパラメータがCDBレベルでOFFに設定されている場合は、PDBまたはセッション・レベルで有効にすることはできません。同じロジックがPDBおよびセッション・レベルに適用されます。MLEがPDBレベルで無効になっている場合は、セッション・レベルで有効にすることはできません。

ノート:

Oracle Database 23cでは、MLEはJavaScriptを唯一の言語としてサポートしています。パラメータをALLまたはJAVASCRIPTのどちらに設定しても効果は同じです。

ノート:

MLE_PROG_LANGUAGESOFFに設定すると、データベースでのJavaScriptコードの実行は回避されますが、既存のコードの作成や変更は妨げられません。

関連項目:

MLE_PROG_LANGUAGESの詳細は、『Oracle Databaseリファレンス』を参照してください

実行コンテキスト

データベースでJavaScriptコードを実行する場合、MLEは実行コンテキストを使用して、グローバル変数やその他の重要な情報などのランタイム状態を分離します。実行コンテキストは、モジュールおよび環境の使用時には暗黙的に作成され、DBMS_MLEの使用時には明示的に作成されます。

JavaScriptの起動の選択に関係なく、実行コンテキストは情報漏洩を防ぐように設計されています。

JavaScript状態のスコープは、データベース・セッションの存続期間を超えることはありません。セッションが正常または強制的に終了するとすぐに、セッション状態は破棄されます。セッション間で状態を保持する必要がある場合は、スキーマに格納して保持する必要があります。必要に応じて、DBMS_SESSION.reset_package()をコールして状態を破棄できます。

関連項目:

DBMS_SESSIONの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

ランタイム状態の分離

MLEコール仕様は、オプションのMLE環境がアタッチされたMLEモジュール内のファンクションを参照するPL/SQLユニットです。セッションでコール仕様を呼び出すと、対応するMLEモジュールがロードされ、オプションの環境が適用され、コール仕様の署名句で指定されたファンクションが実行されます。

実行を開始する前に、対応する実行コンテキストが(暗黙的に)作成される必要があります。新しい実行コンテキストが作成されるか、既存のコンテキストが再使用されるかは、具体的には次の複数の要因によって決まります:

  • コール仕様で参照されるMLEモジュール

  • 対応するMLE環境

  • コール仕様を実行するデータベース・ユーザー

情報漏洩や、モジュール内のグローバル変数が誤って上書きされるなどの望ましくない副作用を防ぐために、個別の実行コンテキストが作成されます。

コール仕様が呼び出されるたびに、追加の実行コンテキストが作成されます。これは、モジュールが相互に干渉しないようにするために行われます。

ユーザー・セッションで実行コンテキストを作成するための主な基準は、MLEモジュール名と対応するMLE環境です。MLEモジュールと環境の様々な組合せを参照するコール仕様によって、異なる個別の実行コンテキストが作成されます。

コール仕様を呼び出すユーザーに基づいて、実行コンテキスト間のさらなる分離が実行されます。

例9-1 ランタイム状態の分離シナリオ

この例では、ランタイム状態の分離のサンプル・シナリオを示します。データベース・ユーザーUSER1は、次のMLEスキーマ・オブジェクトを作成します:

CREATE OR REPLACE MLE MODULE isolationMod LANGUAGE JAVASCRIPT AS

let id;      // global variable

export function doALotOfWork() {
  // a dummy function simulating a lot of work
  // the focus is on modifying a global variable

  id = 10;
}

export function getId() {

  return (id === undefined ? -1 : id)
}
/

CREATE OR REPLACE MLE ENV isolationEnv;

CREATE OR REPLACE PACKAGE context_isolation_package AS

  -- initialise runtime state
  procedure doALotOfWork as 
    mle module isolationMod 
    signature 'doALotOfWork()';
  
  -- access a global variable (part of session state)
  function getId return number as 
    mle module isolationMod 
    signature 'getId()';

  -- same function signature as before but referencing an environment
  function getIdwEnv return number as 
    mle module isolationMod 
    env isolationEnv
    signature 'getId()';
END;
/

USER1 (MLEモジュール、環境およびコール仕様(パッケージ)の所有者)がcontext_isolation_package.doALotOfWork()をコールすると、グローバル変数(id)が10に初期化されます。

BEGIN
    context_isolation_package.doALotOfWork();
END;
/

context_isolation_package.getId()context_isolation_package.doALotOfWork()と同じMLEモジュールおよび同じ(デフォルト)環境を参照するため、ユーザーのセッションはグローバル変数にアクセスできます:

SELECT CONTEXT_ISOLATION_PACKAGE.getId;

     GETID
----------
        10

ユーザー、MLEモジュールおよび環境の組合せが変更されると、新しい実行コンテキストが作成されます。context_isolation_package.getIdwEnv()getID()と同じMLEモジュールを参照し、ユーザーは変更されませんが、このファンクションは、以前に作成した実行コンテキストからグローバル変数の値を取得できません:

SELECT CONTEXT_ISOLATION_PACKAGE.getIdwEnv;

 GETIDWENV
----------
        -1

-1は、JavaScriptモジュールのグローバル変数が初期化されていないことが判明したことを示します。

MLEコール仕様の所有者であるUSER1がパッケージに対する実行権限を別のユーザー(USER2など)に付与すると、同じファンクションがコールされても、USER2に対して別の実行コンテキストが作成されます:

GRANT EXECUTE ON CONTEXT_ISOLATION_PACKAGE TO user2;

USER2IDの値を読み取ろうとすると、新しいコンテキストが作成され、初期化されていないコンテキストを示す戻り値が戻されます:

SELECT user1.CONTEXT_ISOLATION_PACKAGE.getid;

     GETID
----------
        -1

この例では、コール仕様に従って、モジュールおよび環境はUSER1USER2の間で同一です。ただし、別のユーザーがそのファンクションをコールすると、新しい実行コンテキストが作成されます。

データベース・セキュリティ・モデル

プログラム・ユニット、アカウントおよびロールに付与される権限は少なければ少ないほど不正に使用されにくくなります。すべてのアプリケーションと同様に、必要な最小数の権限のみを付与するという原則に従う必要があります。これは、本番環境のような上位層の環境で特に当てはまります。権限分析などのテクノロジを使用して不要な権限を追跡できるため、回帰テストを慎重に行った後に権限を取り消すことができます。

MLEコール仕様は、独自のセキュリティ・コンテキスト内で作成されます。コンテキストには、次のような情報が含まれます:

  • AUTHID句の値(定義者または実行者)

  • 実行者権限のコールで権限を継承するかどうか

  • コード・ベース・アクセス制御

  • 現在のユーザー

  • 修飾スキーマ名

  • コード・ベース・アクセス制御(CBAC)および実行者権限がない場合に有効なロールおよび権限

これらの属性の組合せにより、MLEコール仕様やモジュールなどのコード・ユニットのセキュリティ・コンテキストが形成されます。MLEモジュールに格納されているJavaScriptコードには、そのようなセキュリティ・コンテキストは存在しないことに注意してください。

PL/SQLを使用すると、PL/SQLユニットごとにこれらの属性を簡単に変更できます。プロシージャは実行者権限または定義者権限で実行でき、ロールはPL/SQLユニットにアタッチでき、スキーマ間の(実行)権限は一般的です。PL/SQLユニットが実行されるたびに、セキュリティ・コンテキストが変更される可能性があります。これは、MLEコール仕様にも同様に適用されます。

JavaScriptコードの場合は状況が異なります。JavaScriptからJavaScriptへのコールでは、セキュリティ・コンテキストは変更されません。JavaScriptファンクションには、関連する実行者権限や定義者権限、またはファンクション自体に付与されたロールの概念はありません。これらはすべて、(PL/SQL)コール仕様にのみ適用されます。

DBMS_MLEを使用して実行されるJavaScriptは、セキュリティ・コンテキストに関してはもう少し厳密です。現在アクティブなユーザー、ロール/権限および有効なスキーマの組合せは、DBMS_MLE.create_context()をコールして実行コンテキストが作成されたときに記録されます。この組合せは、JavaScriptコードが実行されてコンテキストが削除されるまで変更しないでください。そうしないと、エラーがスローされます。

関連項目:

権限分析の詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください

異なるスキーマのMLEコール仕様およびモジュールを使用する際の考慮事項

PL/SQLなどで記述された他のデータベース・アプリケーションに使用されるのと同じ考慮事項が、MLE JavaScriptコードにも適用されます。ユーザーに自分以外のスキーマからコードを実行するためのアクセス権が付与されている場合は、コードがコール元のユーザーの権限を適切な範囲で使用できることを慎重に確認するする必要があります。

PL/SQLとは異なり、MLEモジュールに格納されているMLE JavaScriptコードは、特定のロール・セットや、JavaScriptコードが実行されるセキュリティ・コンテキストを決定するその他の概念に関連付けられていません。概して、スキーマ間での権限の使用には次の2つの重要なケースがあります:

  1. USER1は、USER2のスキーマにあるコール仕様を呼び出します。USER2のスキーマのコール仕様のAUTHID句により、USER2のスキーマが所有するコードが実行者(USER1)と定義者(USER2)のどちらの権限で実行されるかが決まります。実行者権限のコール仕様の場合、潜在的にアタッチされたロール(CBAC)およびINHERIT PRIVILEGESの設定により、ロールまたは直接付与によってUSER1によって付与されるロールと権限に加えて、アクティブなロールと権限が決まります。

  2. USER1は、USER1が所有するモジュールModule_Aのコール仕様CallSpec_Aを作成します。CallSpec_Aは、別のスキーマUSER2が所有するJavaScriptモジュールModule_Bをインポートします。Module_BのJavaScriptコードは、USER1のコール仕様CallSpec_A用に作成された実行コンテキストにインポートされます。Module_BのJavaScriptコードは、Module_Aなど、この実行における他のJavaScriptコードと同じ権限で実行されます。USER1は、Module_Bのコードが信頼できること、およびこれらの権限で実行することが適切であることを確認する必要があります。

関連項目:

定義者権限および実行者権限のPL/SQLユニットのロールの詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください

Oracle DatabaseでのMLE操作の監査

監査とは、構成されたデータベース・アクションの監視および記録ですOracle Databaseの他の監査可能な操作と同様に、MLE関連のシステム権限の使用を記録できます。

データベースには、ORA_SECURECONFIG監査ポリシーが提供されています。Oracle Databaseリリース23c以降、監査ポリシーには次のMLEシステム権限の使用が含まれています:

  • CREATE ANY MLE

  • ALTER ANY MLE

  • DROP ANY MLE

管理者およびセキュリティ・チームは、MLEスキーマ・オブジェクト(MLEモジュール、環境およびコール仕様を含む)の作成を監査する必要がある場合、追加のセキュリティ・ポリシーを作成して有効にする必要があります。

関連項目:

Oracle Databaseでの監査の詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください

JavaScriptセキュリティのベスト・プラクティス

JavaScriptでMLEの機能を使用する場合のベスト・プラクティスに関する詳細を説明しています。

トピック

セキュリティおよびパフォーマンスのためのバインド変数の使用

MLE JavaScript SQLドライバを使用すると、文字列の連結を使用して、問合せおよびDML文で使用される述語を含むSQLコマンドを作成できます。この方法はSQLインジェクション攻撃の主な発生原因となるため適切ではなく、使用しないことをお薦めします。SQL文でのバインド変数の使用は、文字列の連結よりも安全であり、さらにデータベースが共有プールでカーソルを再利用できるため、より効率的です。

動的SQLの作成を回避できない場合は、必ず、コードへの入力を検証し、悪意のあるコンテンツがないかどうかをスキャンするようにします。組込みのDBMS_ASSERTパッケージは、SQLインジェクション攻撃を軽減するように設計された豊富な機能を提供します。完全な保護は提供しませんが、次のことを検証できるため、使用することをお薦めします:

  • 入力文字列が修飾SQL名であること

  • 入力文字列が既存のスキーマ名であること

  • 入力文字列が単純SQL名であること

  • 入力パラメータ文字列が既存のSQLオブジェクトの修飾SQL識別子であること

セキュリティおよびスケーラビリティを向上させるためにバインド変数を使用することは、JavaScriptなどの1つのプログラミング言語に限定されず、Oracle Databaseを使用するすべての開発プロジェクトに同様に適用されます。

関連項目:

例9-2 文字列の連結ではなくバインド変数を使用する

この例では、SELECT文は、入力変数managerIDをSQLコマンドに連結するのではなく、バインド変数を受け入れます。

CREATE OR REPLACE MLE MODULE select_bind LANGUAGE JAVASCRIPT AS

import oracledb from "mle-js-oracledb";

export function numEmployeesByManagerID(managerID) {

  const conn = oracledb.defaultConnection(managerID);
  const result = conn.execute(
    `SELECT count(*) FROM employees WHERE manager_id = :1`,
    [ managerID ]
  );

  return result.rows[0][0];
}
/

例9-3 DBMS_ASSERTを使用した有効な入力の検証

この例では、ファンクションcreateTempTable()によって、バッチ・プロセスの中間結果を保持するプライベート一時表が作成されます。このファンクションでは、1つの引数(作成する一時表の名前から接頭辞を除いたもの)を使用します。このファンクションは、渡されたパラメータが有効なSQL名かどうかをチェックします。

CREATE OR REPLACE MLE MODULE dbms_assert_module LANGUAGE JAVASCRIPT AS

import oracledb from "mle-js-oracledb";

export function createTempTable(tableName) {
  const conn = oracledb.defaultConnection();
  let result; 
  let validTableName; 

  try {
    result = conn.execute(
      `SELECT dbms_assert.qualified_sql_name(:tableName)`, 
      [tableName]
    );
    validTableName = result.rows[0][0];
  } catch (err) {
    throw (`'${tableName}' is not a valid table name`);
    return;
  }

  result = conn.execute(
    `CREATE PRIVATE TEMPORARY TABLE ora\$ptt_${validTableName} (id number)`
  );
}
/

ファンクションに渡された表名がテストに合格した場合は、この表名を使用して、デフォルトのprivate_temp_table_prefixを使用してプライベート一時表が作成されます。

汎用データベースおよびPL/SQL固有のセキュリティに関する考慮事項

すべてのJavaScriptコードは最終的にPL/SQLコール仕様を介してアクセスされるため、PL/SQLを使用する意味を理解することも重要です。次の概念は特に重要です:

  • 実行者権限と定義者権限の違い

  • コード・ベース・アクセス制御(CBAC)

  • 実行者権限コードにおけるINHERIT PRIVILEGESの影響

  • ロール付与と直接付与(オブジェクト権限とシステム権限の両方)

JavaScriptコードの実行には、常に最小限のセキュリティ権限(オブジェクトおよびシステム)のみが必要になるようにしてください。これは、外部のサード・パーティのJavaScriptコードの使用を検討する場合に特に重要です。

管理者は、保存中のデータと移動中のデータの両方に暗号化を使用することを検討する必要があります。

関連項目:

サプライ・チェーンのセキュリティ

豊富なコミュニティ・エコシステムへのアクセスは、Oracle DatabaseでJavaScriptを使用する利点の1つです。機能を社内で作成する(重複作業が発生する可能性もあるある)のではなく、かわりに既存のJavaScriptを使用できます。これはアプリケーションを開発する方法として便利ではありますが、特定のリスクを伴います。

過去数年間、人気の高い特定のオープン・ソースのJavaScriptモジュールが元のメンテナによって放棄されたという事実を表現するサプライ・チェーン・アタッチという用語が使用されてきました。残念ながら、悪意のあるアクターがこれらのプロジェクトのいくつかのメンテナになり、悪意のあるコードをソースに挿入しています。その後、プロジェクトがそのような危険性のあるモジュールを参照すると、悪意のあるコードが組み込まれます。

クライアント側の開発に適用されるのと同じ原則が、MLEを使用したサーバー側の開発にも適用されます。開発者およびセキュリティ・チームは、アプリケーション内のコードが実行されるときの権限が昇格される可能性があることを認識する必要があります。これらは悪意のあるコードによって悪用され、アプリケーションの機密性、整合性および可用性のプロパティが不正使用される可能性があります。そのため、サード・パーティのコードが信頼できること、および最小数の権限が付与されていることを慎重に確認する必要があります。多くの企業には、オープン・ソース・モジュールの使用を承認する前に審査する専用のセキュリティ・チームがあります。少なくとも、プロジェクトに含めるJavaScriptコードを監査し、結果を文書化する必要があります。

package-lock.jsonファイルのようなメカニズムを使用して、オープン・ソース・モジュールの特定のバージョンをロックして、モジュールの新しいバージョンが配布された場合に更新対象にならないようにできます。外部コードの依存関係の最新バージョンを自動的にプルする方法は好ましくないため、常に避ける必要があります。

MLEのJavaScriptの場合、JavaScriptコードは、関連付けられた実行コンテキストに対して有効なデータベース権限で実行されます。JavaScriptコードは、これらの権限に従って、データベースに格納されているデータを取得および変更できます。悪意のあるコードはこれらの権限を利用して、不適切な方法でデータベースを変更する可能性があります。

したがって、MLEモジュールを作成する権限は慎重に付与し、必要不可欠な環境でのみ付与してください。可能な場合は、[CREATE | ALTER | MODIFY] ANYシステム権限を付与しないようにしてください。

また、実行者権限プロシージャのコンテキストでINHERIT PRIVILEGES設定を確認する必要があります。業界のベスト・プラクティスに従ってINHERIT PRIVILEGESの設定を確認および保護した後に、MLEコール仕様に実行者権限を使用することを検討してください。

コード・ベース・アクセス制御(CBAC)を実装することで、実行者権限プロシージャに対するより高いレベルの追加のセキュリティを実現できます。CBACを使用すると、開発者は、スキーマまたは実行者の権限を昇格させる必要なく、ロールをPL/SQLユニットに関連付けることができます。

関連項目:

INHERIT PRIVILEGES権限の詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください

ソフトウェア部品構成表

プロジェクトに含まれる外部コードに依存するすべてのプロジェクトは、デプロイ済アプリケーション・アーティファクトにバンドルされているすべてのソフトウェア・コンポーネントのレコード(バージョンを含む)を保持するようにすることをお薦めします。

ソフトウェア部品構成表(SBOM)は、新しく公開された脆弱性に迅速に対応することが最も重要な場合に使用する主要なツールです。エクスプロイトは、脆弱性が公開された直後にほぼ確実に使用されます。使用中のサード・パーティ・ライブラリのバージョンを正確に把握しておくことで、対応の準備にかかる時間を大幅に節約できます。

実際のコードの格納に加えて、MLEモジュールにはメタデータ・フィールドがあり、このフィールドを使用して任意のメタデータをモジュールに格納できます。特に、モジュールにバンドルされているすべてのJavaScriptライブラリを記述するSBOMを格納するために使用できます。このフィールドは、MLEランタイムによって解釈されません。コンテンツとフォーマットは全体的に任意です。

関連項目:

MLEモジュールの作成およびモジュールへのメタデータの提供の詳細は、「MLE JavaScriptモジュールおよび環境」を参照してください

データベースを使用した状態の格納

MLE JavaScriptコードを使用してアプリケーションを記述する場合は、アプリケーション状態を表に格納するなどの確立されたパターンから逸脱しないようにします。これにより、Oracle Databaseで使用可能な豊富なセキュリティ機能を最大限に活用できます。

特に、1つのストアド・プロシージャまたはファンクション・コールの境界を越えるJavaScript状態に依存しないようにしてください。

Oracle DatabaseはJSONを強力にサポートしており、リレーショナルとNoSQL APIの両方を提供しています。データベースのJSON APIは、状態を格納するMLE JavaScriptコードでは当然の候補です。Oracle Databaseに状態を格納すると、特にデータの永続性およびトランザクションの一貫性に関して、アプリケーション状態よりも優れたプログラミング・モデルが提供されます。

関連項目:

Oracle DatabaseでのJSONの使用の詳細は、『Oracle Database JSON開発者ガイド』を参照してください

例9-4 文字列の連結ではなくバインド変数を使用する

この例では、SELECT文は、入力変数managerIDをSQLコマンドに連結するのではなく、バインド変数を受け入れます。

CREATE OR REPLACE MLE MODULE select_bind LANGUAGE JAVASCRIPT AS

import oracledb from "mle-js-oracledb";

export function numEmployeesByManagerID(managerID) {

  const conn = oracledb.defaultConnection(managerID);
  const result = conn.execute(
    `SELECT COUNT(*) FROM employees WHERE manager_id = :1`,
    [ managerID ]
  );

  return result.rows[0][0];
}
/

例9-5 DBMS_ASSERTを使用した有効な入力の検証

この例では、ファンクションcreateTempTable()によって、バッチ・プロセスの中間結果を保持するプライベート一時表が作成されます。このファンクションでは、1つの引数(作成する一時表の名前から接頭辞を除いたもの)を使用します。このファンクションは、渡されたパラメータが有効なSQL名かどうかをチェックします。

CREATE OR REPLACE MLE MODULE dbms_assert_module LANGUAGE JAVASCRIPT AS

import oracledb from "mle-js-oracledb";

export function createTempTable(tableName) {
  const conn = oracledb.defaultConnection();
  let result; 
  let validTableName; 

  try {
    result = conn.execute(
      `SELECT dbms_assert.qualified_sql_name(:tableName)`, 
      [tableName]
    );
    validTableName = result.rows[0][0];
  } catch (err) {
    throw (`'${tableName}' is not a valid table name`);
    return;
  }

  result = conn.execute(
    `CREATE PRIVATE TEMPORARY TABLE ora\$ptt_${validTableName} (id number)`
  );
}
/

ファンクションに渡された表名がテストに合格した場合は、この表名を使用して、デフォルトのprivate_temp_table_prefixを使用してプライベート一時表が作成されます。

マルチリンガル・ランタイムの無効化

JavaScriptコードでセキュリティの脆弱性が検出された場合、JavaScriptランタイムを無効にしてJavaScriptコードが実行されないようにできます。初期化パラメータMLE_PROG_LANGUAGESOFFに設定すると、データベースが新しいコードを受け入れることは妨げられず、コード修正の実装を妨げるような動作は発生しませんが、JavaScriptコードの実行が停止されます。

アプリケーションは、そのオプションを考慮して記述する必要があります。MLEランタイムが無効になると、エラーがスローされます。エンド・ユーザーに未処理エラーを表示するのではなく、より理解しやすいエラー・メッセージを作成する必要があります。

JavaScriptには特定のロックダウン機能はありませんが、MLE_PROG_LANGUAGESパラメータを使用すると、セッション、PDB (ロックダウン・プロファイルはこのレベルで動作)またはCDBレベルでMLEランタイムを無効にできます。ロックダウン・プロファイルのCOMMON_SCHEMA_ACCESS機能バンドルを使用して、MLE DDLを無効にできます。

MLEのセキュリティの例

シナリオ例を使用して、MLEで使用されるセキュリティ機能を示します。例では、MLEモジュール、環境、および利用される機能を有効にするために必要な権限付与の間で様々な分離度を使用しています。

これらの例は、単独では完全に使用できるわけではないことに注意してください。実際のJavaScriptコードは、次のようなアプリケーションの構造ほど重要ではありません:

  • コードが存在するスキーマ

  • コール仕様の構文

  • 付与されたロールおよび権限

トピック

MLEモジュールに格納されたビジネス・ロジック

このシナリオでは、ユーザーは、特定のスキーマにバインドされたJavaScriptに実装された機能を提供し、特定の権限を持つ特定のユーザーとして実行することに依存します。

このシナリオでは、必要なすべての表、索引などを含む単一のスキーマを中心としたバックエンド・アプリケーションの典型的なケースについて説明します。最も重要なことは、ビジネス・ロジックは、データベースにストアド・コードとして実装されることです。

MLEモジュールおよびMLE環境の形式でのJavaScriptの実装は、単一のスキーマにカプセル化されます。この機能へのアクセスは、1つ以上のモジュールに基づくMLEコール仕様を使用してのみ公開されます。アプリケーションのユーザーには、(PL/SQL)コール仕様に対する実行権限のみが付与されます。MLEモジュールおよび環境に対するそれ以上の権限は付与されず、必要もありません。

したがって、MLEモジュールの所有者は、MLEコール仕様にアタッチされたAUTHID句を使用して、アプリケーションへのアクセスを制御します。例9-6の擬似コードは、このシナリオを示しています。

例9-6 MLEモジュールに格納されたビジネス・ロジック

この例では、アプリケーション・スキーマはAPP_OWNERと呼ばれます。MLEモジュールおよび環境がどのようにAPP_OWNERスキーマに制限されているかに注意してください。

-- MLE Module containing helper functions commonly used by the application
CREATE MLE MODULE app_owner.helper_module LANGUAGE JAVASCRIPT AS 

export function setDebugLevel(level) {
  // ... JavaScript code ...
}

// ... additional functionality ...
/

-- An MLE Environment allowing other MLE Modules to import the helper module
CREATE MLE ENV app_owner.helper_module_env IMPORTS (
  'helperModule' module helper_module
);

-- The main application module imports the helper module for common tasks
CREATE MLE MODULE app_owner.orders_module LANGUAGE JAVASCRIPT AS

import { setDebugLevel } from "helperModule";

export function newOrder() {

setDebugLevel("INFO");
  // ... JavaScript code ...
}

export function delivery() { 
  setDebugLevel("WARN");
  // ... JavaScript code ...
}

// ... additional functionality ...
/

-- The call specification is all the end users need to be granted
-- access to. The execute privilege to this definer's rights procedure 
-- (created and executed with the app_owner’s database privileges) 
-- is all that needs granting to the application role.

CREATE app_owner.package orders_pkg AS

  PROCEDURE new_order AUTHID DEFINER AS
    MLE MODULE orders_module
    ENV helper_module_env
    SIGNATURE 'newOrder()';
  
  PROCEDURE delivery AUTHID DEFINER AS
    MLE MODULE orders_module
    ENV helper_module_env
    SIGNATURE 'delivery()';

END order_pkg;
/

GRANT EXECUTE ON app_owner.package orders_pkg TO app_role;

汎用的なデータ処理ライブラリ

このシナリオでは、汎用的なJavaScript機能が、1つのデータベース・スキーマ内で論理的にグループ化されています。JavaScriptコードは、機能的にも論理的にも既存のデータベース・オブジェクトに関連付けられていません。つまり、処理ロジックはステートレスです。

表やビューなどのデータベース・スキーマ・オブジェクトとは関係がないため、オブジェクトの権限付与は関係ありません。JavaScriptコードは、ファンクションの引数のみを変換します。このようなライブラリの例としては、機械学習コード、イメージ操作(スケーリング、クロッピング、解像度の変更など)などがあります。その他のユースケースとしては、入力の検証やJSON処理などがあります。

このような方法でデプロイされたMLEモジュールの主な目的は、独自のアプリケーションで使用できるJavaScriptツールの共通セットを提供することです。そのため、事前定義されたMLEコール仕様は提供されていません。かわりに、これらのモジュールを含むスキーマは、MLEモジュールに対する実行権限を付与します。ユースケースに一致するMLEコール仕様の定義は、権限受領者が行います。必要に応じて、MLE環境をMLEモジュールと一緒に作成し、作成した機能の使用を希望する開発者にそれぞれの権限を付与できます。例9-7は、このシナリオを示しています。

例9-7 汎用的なデータ処理ライブラリ

-- Common functionality potentially referenced by multiple applications
-- is grouped in a database schema. This particular MLE Module provides
-- input validation
CREATE MLE MODULE library_owner.input_validator_module
  LANGUAGE JAVASCRIPT USING BFILE(js_src_dir, 'input_validator.js');
/

-- Another MLE module provides common machine learning functionality
CREATE MLE MODULE library_owner.commom_ml_module
  LANGUAGE JAVASCRIPT USING BFILE(js_src_dir, 'commom_ml_lib.js');
/

-- Rather than a Call Specification as demonstrated in Example 9-6,
-- this time the MLE Modules themselves are exported for use
-- in a different schema: frontend_app 
GRANT EXECUTE ON library_owner.input_validator_module TO frontend_app;
GRANT EXECUTE ON library_owner.commom_ml_module TO frontend_app;

-- frontend_app makes explicit use of a select few functions exported
-- by the MLE modules
CREATE PACKAGE input_validator_pkg AS

  FUNCTION checkEMail(p_email VARCHAR2) RETURN BOOLEAN AS
    MLE MODULE library_owner.input_validator_module
    SIGNATURE 'checkEmail(string)';
  
  FUNCTION checkZIPCode(p_zipcode VARCHAR2) RETURN BOOLEAN AS
    MLE MODULE library_owner.input_validator_module
    SIGNATURE 'checkZIPCode(string)';
  
  -- additional functionality ...
END;
/

一般的なステートレスJavaScriptコードのグループ化は、単一のスキーマに限定されません。機能やメンテナごとにさらに分離することも可能です。

ビジネス・ロジックの汎用的なライブラリ

このシナリオでは、単一のスキーマに含まれるビジネス・ロジックを利用し、汎用的なライブラリを使用して機能を拡張します。

この例では、例9-6および例9-7で示したシナリオを拡張します。ドメイン固有のビジネス・ロジックでは、ロギングやデバッグなどの共通機能による拡張が必要になる場合があります。後者は汎用的に記述できるため、他のアプリケーションにも含めることができます。そのアプローチには多くの利点があり、それは補助機能のための統合フレームワークに限定されません。

例9-8では、例9-6で定義されたAPP_OWNERのスキーマのビジネス・ロジックが、すでに例9-7で導入された検証機能と機械学習機能で拡張されています。

データベース内のMLEモジュールおよび環境を操作する場合の最善の方法として一定のものはありません。常に特定のユースケースに依存します。含まれている例では、プロジェクトのニーズに応じて、アプリケーション・ロジックをグループ化または分離する方法の背景を単に示しています。

例9-8 ビジネス・ロジックでの汎用的なライブラリの使用

-- Centrally managed JavaScript code library in the LIBRARY_OWNER schema
CREATE MLE MODULE library_owner.commom_ml_module
  LANGUAGE JAVASCRIPT USING BFILE(js_src_dir, 'commom_ml_lib.js');
/

-- The grant makes the module available to APP_OWNER
GRANT EXECUTE ON library_owner.commom_ml_module TO app_owner;

-- Business logic in schema APP_OWNER makes use of the common ML library
CREATE MLE MODULE app_owner.helper_module LANGUAGE JAVASCRIPT AS 

export function setDebugLevel(level) {
  // ... JavaScript code ...
}

// ... additional functionality ...
/

-- A generic MLE environment references both APP_OWNER's as well as 
-- LIBRARY_OWNER's MLE modules
CREATE MLE ENV app_owner.all_dependencies_env imports (
  'helperModule' module helper_module
  'commonML'     module library_owner.commom_ml_module
);

-- The main application module imports the helper module for common tasks
-- as well as the common machine learning module provided by LIBRARY_OWNER
CREATE MLE MODULE app_owner.orders_module LANGUAGE JAVASCRIPT AS

import { setDebugLevel } from "helperModule";
import { churnRate }     from "commonML";

export function newOrder() {

  setDebugLevel("INFO");
  // ... JavaScript code ...
}

export function delivery() { 
  setDebugLevel("WARN");
  // ... JavaScript code ...
}

export function estimateChurnRate() {

  // This function was imported from the common ML library
  // (an MLE module not stored in APP_OWNERs schema)
  const cr = churnRate();

  // ... JavaScript code ...
}

// ... additional functionality ...
/

-- the call specification is all the end-users need to be granted
-- access to. The execute privilege to this definer rights procedure 
-- (created and executed with the app_owner’s database privileges) 
-- is all that needs granting to the application role.

CREATE app_owner.package orders_pkg AS

  PROCEDURE new_order AUTHID DEFINER AS
    MLE MODULE orders_module
    ENV all_dependencies_env
    SIGNATURE 'newOrder()';
  
  PROCEDURE delivery AUTHID DEFINER AS
    MLE MODULE orders_module
    ENV all_dependencies_env
    SIGNATURE 'delivery()';
  
  FUNCTION estimateChurnRate AUTHID DEFINER AS
    MLE MODULE orders_module
    ENV all_dependencies_env
    SIGNATURE 'estimateChurnRate()';

END order_pkg;
/