セキュリティ・ガイド
このセキュリティ・ガイドでは、GraalVMのセキュリティ・モデルと機能に関する情報を、それに基づいてセキュアなアプリケーションを構築することを目指す開発者および埋込み担当者に提供します。読者にGraalVMアーキテクチャに関する知識があることを前提としています。このガイドは、Javaのセキュリティ・ドキュメントに置き換わるものではなく、GraalVM固有の側面で補足するものです。また、セキュリティ研究者にGraalVMのセキュリティ・モデルに関する情報を提供します。
- セキュリティ・モデル
- 言語ランチャ
- ゲスト・アプリケーション
- ネイティブ・イメージ
- セキュリティ・マネージャおよび信頼できないコード
- GraalVM EnterpriseからGraalVM Communityへのダウングレード
セキュリティ・モデル
GraalVMは共有ランタイムです。上位レベルのプログラミング言語(またはその中間表現)の命令を後で実行される入力として受け入れます。GraalVMによって実行されているコードでアプリケーションのセキュリティ制御(アクセス制御など)を実装する開発者は、命令の正しい実行を確保できます。GraalVM上で実行されている、このようなセキュリティ制御をバイパスできるセキュリティ・クリティカルなコードの不適切な実行は、セキュリティの脆弱性とみなされます。
GraalVMでは、信頼できないコードの実行はサポートされていません。GraalVMのお客様が、信頼できない敵対的な可能性があるコードをすぐに実行する必要がある場合は、適切な外部分離プリミティブを採用して、アプリケーション・データの機密性と整合性を確保することをお薦めします。
デバッグ機能は、アプリケーションへの特権アクセスを提供し、その状態と動作を検査および変更できるため、信頼できる環境でのみ使用する必要があります。これらは、さらにネットワーク・ソケットを開いて、デバッグ・クライアントが接続できるようにする場合があります。
GraalVMの試験段階の機能は本番での使用を意図しておらず、セキュリティ・ガイドに記載されていないセキュリティ制限がある場合があります。
脆弱性の報告ガイドに記載されているプロセスを通じて、セキュリティ・モデルを壊すバグをご報告いただくことを歓迎します。
言語ランチャ
Truffleフレームワークで実装される、GraalVMに付属しているすべての言語に対して、対話型シェルなどのランチャが用意されています。これらのランチャは同じように動作し、元のランチャと同じセキュリティ保証が付属しています。
ゲスト・アプリケーション
GraalVMでは、JVMベースの言語で記述されたホスト・アプリケーションが、ポリグロットAPIを介してTruffle言語で記述されたゲスト・アプリケーションを実行できます。コンテキストを作成するとき、ホスト・アプリケーションはゲストがアクセスできるリソースを制御できます。このメカニズムはJavascriptでのみ完全にサポートされています。デフォルトでは、すべての管理対象リソースへのアクセスが拒否され、最小権限の原則に従って明示的に付与される必要があります。
ホストの相互運用性
GraalVMでは、ホスト・アプリケーションとゲスト・アプリケーションの間でオブジェクトを交換できます。デフォルトでは、埋込み機能によって明示的に注釈付けされたホスト・クラスのメソッドのみがゲスト・アプリケーションに公開されます。
セキュリティ上クリティカルなホスト・メソッドを公開することで、アクセス制限を回避できます。たとえば、allowIO=false
を使用して作成されたコンテキスト内のゲスト・アプリケーションは、ゲスト言語のネイティブAPIを介してIO操作を実行できません。ただし、任意のファイルへの書込みを許可するコンテキストにホスト・メソッドを公開すると、この制限が効果的に回避されます。
実行エンジンの共有
アプリケーション開発者は、パフォーマンス上の理由から、実行コンテキスト間で実行エンジンを共有することを選択できます。コンテキストは実行されたコードの状態を保持しますが、エンジンはコード自体を保持します。複数のコンテキスト間で実行エンジンを共有することは明示的に設定する必要があり、多数のコンテキストが同じコードを実行するシナリオではパフォーマンスを向上させることができます。共通コードの実行エンジンを共有するコンテキストが機密(つまり、プライベート)コードも実行するシナリオでは、対応するソース・オブジェクトをコード共有からオプトアウトできます:
Source.newBuilder(…).cached(false).build()
計算リソース制限
ノート: GraalVM Enterpriseで使用できます。
GraalVM Enterpriseは、ゲスト・アプリケーションによって使用される特定の計算リソース(CPU時間、ヒープ・メモリー、コンテキストで同時に使用できるスレッド数など)を制限できます。これらのサンドボックス・オプションは、ポリグロット埋込みAPIを介しても使用できます。
ScriptEngineの互換性
下位互換性の理由から、特定のゲスト言語ではJavaのScriptEngineインタフェースもサポートされています。たとえば、これにより、GraalVM JavaScriptをNashornのドロップイン代替として使用できます。ただし、互換性を維持するために、Nashorn GraalVM JavaScript ScriptEngineインタフェースでは、スクリプトに付与されたすべての権限を持つコンテキストが作成されるため、信頼できるコードに対してのみ細心の注意を払って使用する必要があります。
ネイティブ・コードの管理対象実行
ノート: GraalVM Enterpriseで使用できます。
Truffleフレームワークは、ゲスト言語としてLLVM中間表現(IR)もサポートしています。いくつかのネイティブ・システム・プログラミング言語、特にC/C++は、LLVMコンパイラ・ツールチェーンを使用してLLVM IRにコンパイルできます。通常、これらの言語にはそれ自体ではメモリー安全性がないこと、および、多くの場合、メモリー安全性の違反はセキュリティの脆弱性の原因となることに留意する必要があります。
管理対象モードでは、ネイティブ・レベルへのすべての結合は抽象化され、GraalVM Enterpriseを介してルーティングされます。具体的には、次のことを意味します:
- 一時メモリーと空間メモリー安全性に関しては、メモリーはJavaヒープから割り当てられます。これは、メモリー割当てが管理対象オブジェクトで、かつすべてのアクセスがメモリー安全性のある方法で実行されることを意味します(任意のポインタ演算および未チェックの範囲外アクセスはありません)。
- 型安全性に関しては、データ・ポインタを関数ポインタに再解釈して任意の命令を実行することはできません(これらはLLVMランタイムの個別のポインタ型であるため)。
- システム・コールはインターセプトされ、対応するTruffle APIにルーティングされます。たとえば、ファイルIOはTruffle
FileSystem
APIにマップされます。現在サポートされている一連のシステム・コールは非常に限定的です。Truffle APIレベルに安全にマップできるシステム・コールのみを使用できます。管理対象モードのLLVMランタイムでは、Linux/x86用にコンパイルされたビットコードが常に実行されるため、実装する必要があるのはこのプラットフォームのシステム・コールのみです。 - すべての依存ライブラリも管理対象モードで実行され、ネイティブに実行されたシステム・ライブラリへのすべての参照が削除されます。これには、muslibcなど、LLVMランタイムによって提供されるライブラリが含まれます。
管理対象モードは、コンテキスト(Context.create())
を作成するとき、または--llvm.managed
オプションを指定してbin/lli
バイナリをコールするときに選択できます。管理対象コンテキストは、コンテキストの作成中に渡される制限(allowIO
など)に準拠するため、allowNativeAccess
権限は必要ありません。
ネイティブ・イメージ
native-image
ビルダーは、起動後にアプリケーションのスナップショットを生成し、バイナリ実行可能ファイルにバンドルします。
デフォルトでは、native-image
ビルダーはビルド時にクラスの静的イニシャライザを実行し、イメージ・ヒープに状態を保持します。このことは、静的イニシャライザで取得または計算された情報が、ネイティブ・実行可能ファイルの一部になることを意味します。これにより、イメージ・ヒープ内の環境変数などのビルド環境のプロパティが意図せずに含められる可能性があります。これにより、機密データがスナップショットに含められたり、乱数シードなど、起動時に取得されることが想定される初期化データが修正される可能性があります。
開発者は、ネイティブ実行可能ファイルのビルド時に--initialize-at-run-time
CLIパラメータを指定するか、RuntimeClassInitialization
APIを使用して、機密情報を処理する静的イニシャライザを実行時にかわりに実行するように要求できます。
ネイティブ・イメージには、デフォルトのTrustStoreの定義に使用される証明書ファイルを指定する複数の方法が用意されています。ネイティブ・イメージのデフォルト動作では、ビルド時のホスト環境からデフォルトのTrustStoreを取得して使用されますが、これは実行時にjavax.net.ssl.trustStore*システム・プロパティを設定して変更できます。詳細は、ドキュメントを参照してください。
また、開発者は、コンテナなどの最初から機密情報が含まれていない専用の環境でnative-image
ビルダーを実行できます。
ネイティブ・イメージでのシリアライズ
ネイティブ・イメージではシリアライズがサポートされており、ネイティブ実行可能ファイルに最初から含まれているクラスのコンストラクタをユーザーがデシリアライズできます。他のクラスはデシリアライズできないため、これらのクラスは追加の特定の構成ファイルにホワイトリスト登録する必要があります。デシリアライズのサポートでは、オプションのオブジェクト・チェックサムも追加され、同じチェックサムを持つクラスのみを実行時にデシリアライズできます。チェックサム・メカニズムは、セキュリティ目的で使用しない必要があり、信頼できないデータのデシリアライズはサポートされていません。
セキュリティ・マネージャおよび信頼できないコード
OpenJDK脆弱性グループは、セキュリティ・マネージャの下で信頼できないコードを実行しないことを強く推奨しています。このことは、Javaでの信頼できないコードの実行をサポートしていないGraalVMにも当てはまります。ゲスト言語アプリケーションの実行をある程度制限するGraalVMの機能はセキュリティ・マネージャに依存しませんが、信頼できないコードを実行するためのサンドボックスとして使用するには適していません。
セキュリティ・マネージャの非推奨は、JEP-411のオプションです。
ネイティブ・イメージでは、一般的に、セキュリティ・マネージャはサポートされていません。セキュリティ・マネージャを設定しようとすると、ランタイム・エラーが発生します。
Truffleフレームワークはリソースを管理するための独自の制御を備え、その機能を最大限に活用するには、すべての権限で起動する必要があります。
GraalVM EnterpriseからGraalVM Communityへのダウングレード
ノート: ネイティブ・コードの管理対象実行は、GraalVM Enterpriseで使用できます。
GraalVM Communityにダウングレードする場合、ネイティブ・コードの実行はallowNativeAccess
権限でのみ使用できます。このことは、PythonやRubyなど、Truffleで実装され、ネイティブ・コード拡張を可能にする言語にも適用されます。
計算リソース制限オプションは、GraalVM Communityによって認識されません。