ポリグロット・サンドボックス化

GraalVMでは、JVMベースの言語で記述されたホスト・アプリケーションが、ポリグロット埋込みAPIを介してJavascriptで記述されたゲスト・コードを実行できます。サンドボックス・ポリシーを構成すると、ホスト・アプリケーションとゲスト・コードの間のセキュリティ境界を確立できます。たとえば、ホスト・コードは、UNTRUSTEDポリシーを使用して信頼できないゲスト・コードを実行できます。ホスト・コードは、相互に保護されるゲスト・コードの相互に信頼されないインスタンスを複数実行できます。このようにして、ポリグロット・サンドボックス化でマルチテナント・シナリオがサポートされます:

セキュリティ境界を導入することでメリットを得るユース・ケースは、次のとおりです:

サンドボックス・ポリシー

ユース・ケースおよび関連する許容可能なセキュリティ・リスクに応じて、SandboxPolicy(TRUSTEDからUNTRUSTEDまで)を選択し、より広範囲の制限と軽減策を有効にして構成できます。SandboxPolicyは、事前構成と最終構成の検証の2つの目的を果たします。デフォルトでは、ポリシーに準拠するようにコンテキストおよびエンジンを事前構成します。構成をさらにカスタマイズする場合、ポリシーの検証により、カスタム構成が許容できないほどポリシーを弱めないことが保証されます。

TRUSTEDポリシー

TRUSTEDサンドボックス・ポリシーは、完全に信頼できるゲスト・コードを対象としています。これがデフォルト・モードです。コンテキストまたはエンジン構成に制限はありません。

例:

try (Context context = Context.newBuilder("js")
                              .sandbox(SandboxPolicy.TRUSTED)
                              .build();) {
    context.eval("js", "print('Hello JavaScript!');");
}

CONSTRAINEDポリシー

CONSTRAINEDサンドボックス・ポリシーは、ホスト・リソースへのアクセスを制御する必要がある信頼できるアプリケーションを対象としています。CONSTRAINEDポリシーでは:

例:

try (Context context = Context.newBuilder("js")
                              .sandbox(SandboxPolicy.CONSTRAINED)
                              .out(new ByteArrayOutputStream())
                              .err(new ByteArrayOutputStream())
                              .build()) {
    context.eval("js", "print('Hello JavaScript!');");
}

ISOLATEDポリシー

ISOLATEDサンドボックス化ポリシーはCONSTRAINEDポリシーの上に構築され、実装のバグや信頼できない入力の処理が原因で誤動作する可能性のある信頼できるアプリケーションを対象としています。名前ですでに示されているように、ISOLATEDポリシーはホストとゲスト・コードをより深く分離します。特に、ISOLATEDポリシーで実行されているゲスト・コードは、独自の仮想マシンの別のヒープで実行されます。つまり、JITコンパイラやガベージ・コレクタなどのランタイム要素をホスト・アプリケーションと共有しなくなり、ホストVMはゲストVM内の障害に対する耐障害性が大幅に向上します。

CONSTRAINEDポリシーの制限に加えて、ISOLATEDポリシーには次のような制限があります:

例:

try (Context context = Context.newBuilder("js")
                              .sandbox(SandboxPolicy.ISOLATED)
                              .out(new ByteArrayOutputStream())
                              .err(new ByteArrayOutputStream())
                              .option("engine.MaxIsolateMemory", "256MB")
                              .option("sandbox.MaxCPUTime", "2s")
                              .build()) {
    context.eval("js", "print('Hello JavaScript!');");
}

UNTRUSTEDポリシー

UNTRUSTEDサンドボックス化ポリシーはISOLATEDポリシーの上に構築され、実際の信頼できないコードの実行によるリスクを軽減することを目的としています。信頼できないコードを実行する場合のGraalVMの攻撃対象領域は、コードを実行するゲストVM全体と、ゲスト・コードで使用可能なホスト・エントリ・ポイントで構成されます。

ISOLATEDポリシーの制限に加えて、UNTRUSTEDポリシーには次のような制限があります:

例:

try (Context context = Context.newBuilder("js")
                              .sandbox(SandboxPolicy.UNTRUSTED)
                              .in(new ByteArrayInputStream("foobar".getBytes()))
                              .out(new ByteArrayOutputStream())
                              .err(new ByteArrayOutputStream())
                              .allowHostAccess(HostAccess.UNTRUSTED)
                              .option("engine.MaxIsolateMemory", "8MB")
                              .option("sandbox.MaxHeapMemory", "128MB")
                              .option("sandbox.MaxCPUTime","2s")
                              .option("sandbox.MaxStatements","50000")
                              .option("sandbox.MaxStackFrames","2")
                              .option("sandbox.MaxThreads","1")
                              .option("sandbox.MaxASTDepth","10")
                              .option("sandbox.MaxOutputStreamSize","32B")
                              .option("sandbox.MaxErrorStreamSize","0B");
                              .build()) {
    context.eval("js", "print('Hello JavaScript!');");
}

リソース制限の設定方法の詳細は、対応するガイダンスを参照してください。

ホスト・アクセス

GraalVMを使用すると、ホスト・コードとゲスト・コードの間でオブジェクトを交換し、ホスト・メソッドをゲスト・コードに公開できます。権限の低いゲスト・コードにホスト・メソッドを公開すると、これらのメソッドは、より権限の高いホスト・コードの攻撃対象領域の一部になります。そのため、サンドボックス・ポリシーは、CONSTRAINEDポリシーでホスト・アクセスをすでに制限し、ホスト・エントリ・ポイントを明示しています。

HostAccess.CONSTRAINEDは、CONSTRAINEDサンドボックス・ポリシーの事前定義されたホスト・アクセス・ポリシーです。ホスト・クラス・メソッドを公開するには、@HostAccess.Exportで注釈を付ける必要があります。この注釈は継承されません。ポリグロット・ファイル・システム実装や、標準出力およびエラー・ストリーム・リダイレクション用の出力ストリーム受信者などのサービス・プロバイダは、ゲスト・コード呼出しに公開されます。

ゲスト・コードは、@Implementableの注釈が付いたJavaインタフェースを実装することもできます。このようなインタフェースを使用するホスト・コードは、ゲスト・コードと直接対話します。

ゲスト・コードと対話するホスト・コードは、堅牢な方法で実装する必要があります:

信頼できないゲスト・コードと対話することを認識していないホスト・コードは、前述の側面を考慮せずにゲスト・コードに直接公開しないでください。たとえば、アンチパターンは、サード・パーティ・インタフェースを実装し、すべてのメソッド呼出しをゲスト・コードに転送することです。

リソース制限

ISOLATEDおよびUNTRUSTEDサンドボックス・ポリシーでは、コンテキストのリソース制限を設定する必要があります。コンテキストごとに異なる構成を指定できます。制限を超えた場合、コードの評価は失敗し、isResourceExhausted()に対してtrueを返すPolyglotExceptionでコンテキストは取り消されます。この時点で、そのコンテキストでゲスト・コードを実行することはできなくなります

--sandbox.TraceLimitsオプションを使用すると、ゲスト・コードをトレースし、最大リソース使用率を記録できます。これは、サンドボックスのパラメータの見積りに使用できます。たとえば、Webサーバーのサンドボックス・パラメータは、このオプションを有効にしてサーバーのストレス・テストを行うか、ピーク使用時にサーバーを実行することで取得できます。このオプションを有効にすると、ワークロードの完了後にレポートがログ・ファイルに保存されます。ユーザーは、言語ランチャの場合は--log.file=<path>javaランチャを使用する場合は-Dpolyglot.log.file=<path>を使用して、ログ・ファイルの場所を変更できます。レポート内の各リソース制限をサンドボックス・オプションに直接渡して、制限を適用できます。

たとえば、Pythonワークロードの制限をトレースする方法を参照してください:

graalpy --log.file=limits.log --sandbox.TraceLimits=true workload.py

limits.log:
Traced Limits:
Maximum Heap Memory:                                        12MB
CPU Time:                                                     7s
Number of statements executed:                           9441565
Maximum active stack frames:                                  29
Maximum number of threads:                                     1
Maximum AST Depth:                                            15
Size written to standard output:                              4B
Size written to standard error output:                        0B

Recommended Programmatic Limits:
Context.newBuilder()
            .option("sandbox.MaxHeapMemory", "2MB")
            .option("sandbox.MaxCPUTime","10ms")
            .option("sandbox.MaxStatements","1000")
            .option("sandbox.MaxStackFrames","64")
            .option("sandbox.MaxThreads","1")
            .option("sandbox.MaxASTDepth","64")
            .option("sandbox.MaxOutputStreamSize","1024KB")
            .option("sandbox.MaxErrorStreamSize","1024KB")
            .build();

Recommended Command Line Limits:
--sandbox.MaxHeapMemory=12MB --sandbox.MaxCPUTime=7s --sandbox.MaxStatements=9441565 --sandbox.MaxStackFrames=64 --sandbox.MaxThreads=1 --sandbox.MaxASTDepth=64 --sandbox.MaxOutputStreamSize=1024KB --sandbox.MaxErrorStreamSize=1024KB

ワークロードが変更された場合、または別のメジャーGraalVMバージョンに切り替えた場合は、再プロファイリングが必要になることがあります。

特定の制限は、実行中の任意の時点でリセットできます。

アクティブなCPU時間の制限

sandbox.MaxCPUTimeオプションを使用すると、ゲスト・コードの実行に費やされる最大CPU時間を指定できます。使用されるCPU時間は、基礎となるハードウェアによって異なります。コンテキストがアクティブなまま最大CPU時間を経過すると、自動的に取り消されてクローズされます。デフォルトでは、時間制限は10ミリ秒ごとにチェックされます。これは、sandbox.MaxCPUTimeCheckIntervalオプションを使用してカスタマイズできます。

時間制限がトリガーされるとすぐに、このコンテキストでゲスト・コードを実行できなくなります。起動されるポリグロット・コンテキストのメソッドに対してPolyglotExceptionをスローし続けます。

コンテキストの使用されたCPU時間には、ホスト・コードへのコールバックに費やされた時間が含まれます。

コンテキストで使用されたCPU時間には、通常、同期またはIOの待機に費やされた時間は含まれません。すべてのスレッドのCPU時間が合算され、CPU時間制限と照合されます。これは、2つのスレッドで同じコンテキストが実行された場合、時間制限を2倍速く超えることを意味します。

時間制限は、定期的に呼び出される別の優先度の高いスレッドによって実施されます。指定した精度でコンテキストが取り消される保証はありません。ホストVMで完全なガベージ・コレクションが発生した場合など、精度を大幅に外れる場合があります。時間制限を超えない場合、ゲスト・コンテキストのスループットは影響を受けません。あるコンテキストで時間制限を超えた場合、同じ明示的なエンジンを使用する他のコンテキストのスループットが一時的に低下する可能性があります。

時間を指定するために使用できる単位は、ミリ秒の場合はms、秒の場合はs、分の場合はm、時間の場合はh、日の場合はdです。最大CPU時間制限とチェック間隔はどちらも正の値で、後に時間単位が続く必要があります。

try (Context context = Context.newBuilder("js")
                           .option("sandbox.MaxCPUTime", "500ms")
                       .build();) {
    context.eval("js", "while(true);");
    assert false;
} catch (PolyglotException e) {
    // triggered after 500ms;
    // context is closed and can no longer be used
    // error message: Maximum CPU time limit of 500ms exceeded.
    assert e.isCancelled();
    assert e.isResourceExhausted();
}

実行される文の数の制限

コンテキストが取り消されるまで実行できる文の最大数を指定します。文の制限がトリガーされたコンテキストは使用できなくなり、そのコンテキストの使用のたびにPolyglotException.isCancelled()に対してtrueを返すPolyglotExceptionがスローされます。文の制限は、実行されているスレッドの数とは無関係です。

この制限を負の数に設定して無効にできます。この制限が適用されるかどうかに関係なく、内部ソースはsandbox.MaxStatementsIncludeInternalを使用してのみ構成できます。デフォルトでは、この制限には内部とマークされたソースの文は含まれません。共有エンジンを使用する場合は、1つのエンジンのすべてのコンテキストで同じ内部構成を使用する必要があります。

ゲスト言語によっては、単一の文の複雑度が一定時間ではない場合があります。たとえば、Javascriptの組込み機能(Array.sortなど)を実行する文は単一の文に当たりますが、その実行時間は配列のサイズによって異なります。

try (Context context = Context.newBuilder("js")
                           .option("sandbox.MaxStatements", "2")
                           .option("sandbox.MaxStatementsIncludeInternal", "false")
                       .build();) {
    context.eval("js", "purpose = 41");
    context.eval("js", "purpose++");
    context.eval("js", "purpose++"); // triggers max statements
    assert false;
} catch (PolyglotException e) {
    // context is closed and can no longer be used
    // error message: Maximum statements limit of 2 exceeded.
    assert e.isCancelled();
    assert e.isResourceExhausted();
}

ASTの深度の制限

ゲスト言語関数の最大式の深度の制限。インストゥルメント可能なノードのみが制限に対してカウントされます。

AST深度により、関数の複雑度およびそのスタック・フレーム・サイズを見積もることができます。

スタック・フレーム数の制限

コンテキストがスタック上でプッシュできるフレームの最大数を指定します。スレッドローカルなスタック・フレーム・カウンタが関数の開始時に増分され、関数の終了時に減分されます。

スタック・フレーム制限はそれ自体で、無限再帰に対する保護手段として機能します。ASTの深度制限とともに、スタック領域の合計使用量を制限できます。

アクティブ・スレッド数の制限

コンテキストで同時に使用できるスレッドの数を制限します。マルチスレッドは、UNTRUSTEDサンドボックス・ポリシーではサポートされていません。

ヒープ・メモリー制限

sandbox.MaxHeapMemoryオプションは、ゲスト・コードが実行中に保持できる最大ヒープ・メモリーを指定します。ゲスト・コードに存在するオブジェクトのみが制限に対してカウントされます。ホスト・コードへのコールバック中に割り当てられたメモリーはカウントされません。このオプションの有効性は、使用しているガベージ・コレクタに(も)依存するため、これはハード制限ではありません。これは、ゲスト・コードによって制限を超える可能性があることを意味します。

try (Context context = Context.newBuilder("js")
                           .option("sandbox.MaxHeapMemory", "100MB")
                       .build()) {
    context.eval("js", "var r = {}; var o = r; while(true) { o.o = {}; o = o.o; };");
    assert false;
} catch (PolyglotException e) {
    // triggered after the retained size is greater than 100MB;
    // context is closed and can no longer be used
    // error message: Maximum heap memory limit of 104857600 bytes exceeded. Current memory at least...
    assert e.isCancelled();
    assert e.isResourceExhausted();
}

この制限は、割当て済みバイトまたは低メモリー通知に基づいてトリガーされた保持サイズ計算によってチェックされます。

割り当てられたバイトは、定期的に呼び出される別の優先度の高いスレッドによってチェックされます。メモリー制限されたコンテキストごとにこのようなスレッドが1つ(sandbox.MaxHeapMemoryが設定されたスレッド)あります。保持バイトの計算は、必要に応じて、割り当てられたバイト・チェック・スレッドから起動されるもう1つの優先度の高いスレッドによってさらに行われます。ヒープ・メモリー制限を超えると、保持バイトの計算スレッドもコンテキストを取り消します。さらに、低メモリー・トリガーが呼び出されると、メモリー制限されたコンテキストが少なくとも1つあるエンジン上のすべてのコンテキストが、割当てチェッカとともに一時停止されます。すべての個々の保持サイズ計算は取り消されます。メモリー制限されたコンテキストごとのヒープ内の保持バイトは、単一の優先順位の高いスレッドによって計算されます。

ヒープ・メモリー制限では、コンテキストでOutOfMemoryエラーが発生することは防止されません。多数のオブジェクトを連続して割り当てるゲスト・コードは、オブジェクトをほとんど割り当てないコードと比較して精度が低くなります。

コンテキストの保持サイズ計算は、次に示すエキスパート・オプションsandbox.AllocatedBytesCheckIntervalsandbox.AllocatedBytesCheckEnabledsandbox.AllocatedBytesCheckFactorsandbox.RetainedBytesCheckIntervalsandbox.RetainedBytesCheckFactorおよびsandbox.UseLowMemoryTriggerを使用してカスタマイズできます。

コンテキストの保持サイズ計算は、保持されたバイトの推定が、指定されたsandbox.MaxHeapMemoryの特定の係数を超えるとトリガーされます。推定は、コンテキストがアクティブなスレッドによって割り当てられたヒープ・メモリーに基づきます。より正確には、推定とは、前の保持バイトの計算結果(使用可能な場合)と、前の計算の開始以降に割り当てられたバイト数です。デフォルトでは、sandbox.MaxHeapMemoryの係数は1.0で、sandbox.AllocatedBytesCheckFactorオプションでカスタマイズできます。係数には正の値を指定する必要があります。たとえば、sandbox.MaxHeapMemoryを100MB、sandbox.AllocatedBytesCheckFactorを0.5とします。保持サイズの計算は、割り当てられたバイトが50MBに達したときに最初にトリガーされます。計算された保持サイズが25MBとすると、追加の25MBが割り当てられたときに次の保持サイズの計算がトリガーされます。

デフォルトでは、割り当てられたバイトは10ミリ秒ごとにチェックされます。これは、sandbox.AllocatedBytesCheckIntervalで構成できます。指定可能な最小間隔は1ミリ秒です。より小さい値は1ミリ秒と解釈されます。

同じコンテキストの2つの保持サイズ計算の開始は、デフォルトでは少なくとも10ミリ秒離れている必要があります。これは、sandbox.RetainedBytesCheckIntervalオプションで構成できます。間隔は正数である必要があります。

コンテキストに割り当てられたバイトのチェックは、sandbox.AllocatedBytesCheckEnabledオプションによって無効にできます。デフォルトでは、有効になっています(true)。無効にすると(false)、コンテキストの保持サイズ・チェックは、低メモリー・トリガーによってのみトリガーできます。

ホストVM全体のヒープに割り当てられたバイトの合計数がVMのヒープ・メモリーの合計の特定の係数を超えると、低メモリー通知が起動され、次のプロセスが開始されます。sandbox.MaxHeapMemoryオプションが設定されている実行コンテキストが1つ以上あるすべてのエンジンの実行は一時停止され、メモリー制限されたコンテキストごとにヒープ内の保持バイトが計算され、その制限を超えるコンテキストは取り消されて、実行が再開されます。デフォルトの係数は0.7です。これは、sandbox.RetainedBytesCheckFactorオプションで構成できます。係数は0.0から1.0の間である必要があります。sandbox.MaxHeapMemoryオプションを使用するすべてのコンテキストは、sandbox.RetainedBytesCheckFactorに同じ値を使用する必要があります。

ヒープ・メモリー・プールの使用量しきい値またはコレクション使用量しきい値がすでに設定されている場合は、sandbox.RetainedBytesCheckFactorで指定された制限を実装できないため、デフォルトでは低メモリー・トリガーを使用できません。ただし、sandbox.ReuseLowMemoryTriggerThresholdがtrueに設定され、ヒープ・メモリー・プールの使用量しきい値またはコレクション使用量しきい値がすでに設定されている場合、そのメモリー・プールではsandbox.RetainedBytesCheckFactorの値は無視され、すでに設定されている制限が使用されます。このように、低メモリー・トリガーは、ヒープ・メモリー・プールの使用量しきい値またはコレクション使用量しきい値も設定するライブラリとともに使用できます。

説明されている低メモリー・トリガーは、sandbox.UseLowMemoryTriggerオプションによって無効にできます。デフォルトでは、有効になっています(true)。無効(false)の場合、実行コンテキストの保持サイズ・チェックは、割り当てられたバイト・チェッカによってのみトリガーできます。sandbox.MaxHeapMemoryオプションを使用するすべてのコンテキストは、sandbox.UseLowMemoryTriggerに同じ値を使用する必要があります。

標準出力およびエラー・ストリームに書き込まれるデータ量の制限

実行時にゲスト・コードが標準出力または標準エラー出力に書き込む出力のサイズを制限します。出力のサイズを制限すると、出力に大量に送信するサービス拒否攻撃に対する保護として機能します。

try (Context context = Context.newBuilder("js")
                           .option("sandbox.MaxOutputStreamSize", "100KB")
                       .build()) {
    context.eval("js", "while(true) { console.log('Log message') };");
    assert false;
} catch (PolyglotException e) {
    // triggered after writing more than 100KB to stdout
    // context is closed and can no longer be used
    // error message: Maximum output stream size of 102400 exceeded. Bytes written 102408.
    assert e.isCancelled();
    assert e.isResourceExhausted();
}
try (Context context = Context.newBuilder("js")
                           .option("sandbox.MaxErrorStreamSize", "100KB")
                       .build()) {
    context.eval("js", "while(true) { console.error('Error message') };");
    assert false;
} catch (PolyglotException e) {
    // triggered after writing more than 100KB to stderr
    // context is closed and can no longer be used
    // error message: Maximum error stream size of 102400 exceeded. Bytes written 102410.
    assert e.isCancelled();
    assert e.isResourceExhausted();
}

リソース制限のリセット

Context.resetLimitsメソッドを使用すると、いつでも制限をリセットできます。これは、既知の信頼できる初期化スクリプトを制限から除外する場合に役立ちます。リセットできるのは、文、CPU時間、出力/エラー・ストリームの制限のみです。

try (Context context = Context.newBuilder("js")
                           .option("sandbox.MaxCPUTime", "500ms")
                       .build();) {
    context.eval("js", /*... initialization script ...*/);
    context.resetLimits();
    context.eval("js", /*... user script ...*/);
    assert false;
} catch (PolyglotException e) {
    assert e.isCancelled();
    assert e.isResourceExhausted();
}

実行時防御

engine.SpawnIsolateオプションを使用してISOLATEDおよびUNTRUSTEDサンドボックス・ポリシーによって適用される主な防御は、ポリグロット・エンジンが専用のnative-image分離で動作し、ゲスト・コードの実行を、独自のヒープ、ガベージ・コレクタ、およびJITコンパイラを使用する、ホスト・アプリケーションとは別のVMレベルのフォルト・ドメインに移動することです。

ゲストのヒープ・サイズによってゲスト・コードのメモリー消費にハード制限を設定する以外に、ゲスト・コードのみに実行時防御を集中させることができ、ホスト・コードのパフォーマンスの低下は発生しません。実行時防御は、engine.UntrustedCodeMitigationオプションによって有効になります。

定数ブラインディング

JITコンパイラでは、ユーザーがソース・コードを提供し、ソース・コードが有効であればマシン・コードにコンパイルします。攻撃者の視点から見ると、JITコンパイラは、攻撃者が制御する入力を実行可能メモリー内の予測可能なバイトにコンパイルします。JITスプレーと呼ばれる攻撃では、攻撃者が悪意のある入力プログラムをJITコンパイラにフィードすることによって予測可能なコンパイルを活用し、Return-Oriented Programming (ROP)ガジェットを含むコードを強制的に生成させます。

入力プログラム内の定数は、JITコンパイラがマシン・コードにそのまま含めることが多いため、このような攻撃のターゲットとして特に魅力的です。定数ブラインディングは、コンパイル・プロセスにランダム性を導入することで、攻撃者の予測を無効にすることを目指しています。具体的には、定数ブラインディングは、コンパイル時にランダムなキーで定数を暗号化し、実行時に出現するたびに復号化します。マシン・コードには、暗号化されたバージョンの定数のみがそのまま出現します。ランダム・キーの知識がないと、攻撃者は暗号化された定数値を予測できないため、実行可能メモリー内の結果のバイトを予測できなくなります。

GraalVMは、実行時にコンパイルされたゲスト・コードのコード・ページに埋め込まれたすべての即時値とデータを、4バイトのサイズまでブラインドします。

投機的実行攻撃の軽減

Spectreなどの投機的実行攻撃は、CPUが分岐予測情報に基づいて命令を一時的に実行する可能性があるという事実を悪用します。予測が誤っている場合、これらの命令の結果は破棄されます。ただし、実行によって、CPUのマイクロアーキテクチャ状態に副作用が生じる可能性があります。たとえば、一時的な実行中にデータがキャッシュに取り込まれている場合があります。これは、データ・アクセスのタイミングを合せることで読み取ることができるサイド・チャネルです。

GraalVMは、実行時にコンパイルされたゲスト・コードに投機的実行バリア命令を挿入し、攻撃者が投機的実行ガジェットを作成できないようにすることでSpectre攻撃から保護します。投機的実行バリアは、パターン履歴表に基づいた投機的実行(Spectre V1)を停止するために、条件分岐の各ターゲットに配置されます。投機的実行バリアは、分岐先バッファに基づいた投機的実行(Spectre V2)を停止するために、間接分岐の可能性がある各分岐先にも配置されます。

実行エンジンの共有

異なるトラスト・ドメインのゲスト・コードは、ポリグロット・エンジン・レベルで分離する必要があります。つまり、同じトラスト・ドメインのゲスト・コードのみがエンジンを共有する必要があります。複数のコンテキストで1つのエンジンを共有する場合、それらのすべてに同じサンドボックス・ポリシー(エンジンのサンドボックス・ポリシー)が必要です。アプリケーション開発者は、パフォーマンス上の理由から、実行コンテキスト間で実行エンジンを共有することを選択できます。コンテキストは実行されたコードの状態を保持しますが、エンジンはコード自体を保持します。複数のコンテキスト間で実行エンジンを共有することは明示的に設定する必要があり、多数のコンテキストが同じコードを実行するシナリオではパフォーマンスを向上させることができます。共通コードの実行エンジンを共有するコンテキストが機密(つまり、プライベート)コードも実行するシナリオでは、対応するソース・オブジェクトをコード共有からオプトアウトできます:

Source.newBuilder(…).cached(false).build()

互換性と制限

ポリグロット・サンドボックス化は、GraalVM Community Editionでは使用できません。

サンドボックス化ポリシーに応じて、Truffle言語、インストゥルメントおよびオプションのサブセットのみを使用できます。特に、サンドボックス化は現在、ランタイムのデフォルト・バージョンのECMAScript (ECMAScript 2022)でのみサポートされています。サンドボックス化は、GraalVMのNode.js内からもサポートされていません。

ポリグロット・サンドボックス化は、VMの動作を変更するシステム・プロパティなどによるVM設定への変更と互換性がありません。

サンドボックス化ポリシーでは、セキュア・バイ・デフォルトの状態を維持するために、GraalVMのメジャー・リリース間で互換性のない変更が行われることがあります。

ポリグロット・サンドボックス化では、オペレーティング・システムや基礎となるハードウェアの脆弱性など、その動作環境の脆弱性から保護することはできません。対応するリスクから保護するために、適切な外部分離プリミティブを採用することをお薦めします。

Javaセキュリティ・マネージャとの差別化

Javaセキュリティ・マネージャは、JEP-411のJava 17で非推奨になりました。セキュリティ・マネージャの目的は次のように述べられています: 「セキュリティ・マネージャを使用すると、安全でない可能性がある操作や機密性の高い操作を実行する前に、その操作が何であるか、その操作が実行可能なセキュリティ・コンテキストで試行されているかどうかをアプリケーションが判断できるようになります。」

GraalVMサンドボックスの目標は、信頼できないゲスト・コードをセキュアな方法で実行できるようにすることです。つまり、信頼できないゲスト・コードが、ホスト・コードとその環境の機密性、整合性または可用性を損なうことができないようにすることです。

GraalVMサンドボックスは、次の点でセキュリティ・マネージャとは異なります:

脆弱性の報告

セキュリティの脆弱性が見つかったと思われる場合は、できれば概念実証を添えてsecalert_us@oracle.comにレポートを送信してください。セキュアな電子メールの公開暗号化キーなどの詳細は、脆弱性のレポートを参照してください。報告については、プロジェクトのコントリビュータに直接連絡したり、他のルートを通じて連絡しないようお願いします。