セキュリティとクラスローダーアーキテクチャ
クラスローダーと名前空間
JVMは、ロードするクラスごとに、どのクラスローダー(プリミティブかオブジェクトか)がクラスをロードしたかどうかを追跡します。ロードされたクラスが最初に別のクラスを参照するとき、仮想マシンは、最初に参照クラスをロードしたのと同じクラスローダーから参照されたクラスを要求します。たとえば、仮想マシンがVolcano
特定のクラスローダーを介してクラスをロードする場合、仮想マシンVolcano
は同じクラスローダーを介して参照されているクラスをロードしようとします。がVolcano
という名前のクラスを参照している場合Lava
、おそらくクラス内のメソッドを呼び出すことによりLava
、仮想マシンはLava
ロードしたクラスローダーから要求しVolcano
ます。Lava
クラスローダによって返されたクラスは、動的にクラスにリンクされていますVolcano
。
JVMはクラスのロードにこのアプローチを採用しているため、クラスはデフォルトで、同じクラスローダーによってロードされた他のクラスのみを表示できます。このように、Javaのアーキテクチャでは、単一のJavaアプリケーション内に複数の名前空間を作成できます。名前空間は、特定のクラスローダーによってロードされるクラスの一意の名前のセットです。各クラスローダーについて、JVMは名前空間を維持します。名前空間には、そのクラスローダーを介してロードされたすべてのクラスの名前が入力されます。
Volcano
たとえば、JVMが特定の名前空間に名前が付けられたクラスをロードするとVolcano
、同じ名前空間に名前が付けられた別のクラスをロードすることはできません。Volcano
ただし、Javaアプリケーション内に複数の名前空間を作成できるため、複数のクラスをJVMにロードできます。これは、複数のクラスローダーを作成するだけで実行できます。実行中のJavaアプリケーションで3つの別々の名前空間(3つのクラスローダーのそれぞれに1つ)を作成する場合、Volcano
各名前空間に1つのクラスをロードすることにより、プログラムは3つの異なるVolcano
クラスをアプリケーションにロードできます。
Javaアプリケーションは、同じクラスまたは複数のクラスから複数のクラスローダーオブジェクトをインスタンス化できます。したがって、必要な数(およびさまざまな種類の)クラスローダーオブジェクトを作成できます。異なるクラスローダーによってロードされたクラスは異なる名前空間にあり、アプリケーションが明示的に許可しない限り、相互にアクセスすることはできません。Javaアプリケーションを作成する場合、さまざまなソースからロードされたクラスをさまざまな名前空間に分離できます。このようにして、Javaのクラスローダーアーキテクチャを使用して、さまざまなソースからロードされたコード間の相互作用を制御できます。敵対的なコードが友好的なコードにアクセスして破壊するのを防ぐことができます。
アプレット用のクラスローダー
クラスローダーを使用した動的拡張の1つの例は、クラスローダーオブジェクトを使用してネットワーク経由でアプレットのクラスファイルをダウンロードするWebブラウザです。 Webブラウザーは、HTTPサーバーからクラスファイルを要求する方法を知っているクラスローダーオブジェクト(通常はアプレットクラスローダーと呼ばれます)をインストールするJavaアプリケーションを起動します。アプレットは動的拡張の例です。Javaアプリケーションの起動時に、ブラウザがネットワーク経由でダウンロードするように要求するクラスファイルがわからないためです。ダウンロードするクラスファイルは、ブラウザがJavaアプレットを含むページを検出するため、実行時に決定されます。
Webブラウザによって起動されたJavaアプリケーションは、通常、クラスファイルを取得するネットワーク上の場所ごとに異なるアプレットクラスローダーオブジェクトを作成します。その結果、さまざまなソースからのクラスファイルがさまざまなクラスローダーオブジェクトによってロードされます。これにより、ホストJavaアプリケーション内の異なる名前空間にそれらが配置されます。異なるソースからのアプレットのクラスファイルは別々の名前空間に配置されるため、悪意のあるアプレットのコードが他のソースからダウンロードされたクラスファイルに直接干渉することは制限されています。
クラスローダー間の連携
多くの場合、クラスローダーオブジェクトは、他のクラスローダー(少なくとも基本的なクラスローダー)に依存して、発生するクラスロード要求の一部を実行します。たとえば、クラスファイルをロードする特定の方法がネットワーク経由でダウンロードすることによって実現されるクラスローダーをインストールするJavaアプリケーションを作成するとします。 Javaアプリケーションの実行中に、という名前のクラスをロードするようにクラスローダーから要求が行われたと想定しますVolcano
。
クラスローダーを作成する1つの方法は、最初に原始クラスローダーに、信頼できるリポジトリからクラスを見つけてロードするように依頼することです。この場合、Volcano
はJava APIの一部ではないため、原始クラスローダーがVolcano
。という名前のクラスを見つけることができないと想定します。原始クラスローダーがクラスをロードできないと応答すると、クラスローダーVolcano
はネットワークを介してクラスをダウンロードすることにより、カスタムの方法でクラスのロードを試みることができます。クラスローダーがクラスをダウンロードできたとするとVolcano
、そのVolcano
クラスはアプリケーションの将来の実行過程で役割を果たすことができます。
同じ例を続けるために、しばらくしてからクラスのメソッドがVolcano
初めて呼び出され、そのメソッドがJavaAPIString
からクラスを参照するとします。実行中のプログラムが参照を使用するのは初めてなので、仮想マシンはクラスローダー(ロードしたものVolcano
)にロードを要求しますString
。以前と同様に、クラスローダーは最初に要求を原始クラスローダーに渡しますが、この場合、原始クラスローダーはクラスをクラスローダーに戻すことができString
ます。
原始クラスローダーはString
、この時点で実際にロードする必要がなかった可能性があります。これString
は、Javaプログラムの基本クラスであるため、ほぼ確実に以前に使用されていたため、すでにロードされているためです。ほとんどの場合、原始クラスローダーString
は、信頼できるリポジトリから以前にロードしたクラスを返したばかりです。
原始的なクラスローダーはクラスを見つけることができたので、クラスローダーはネットワークを介してそれをダウンロードしようとはしません。String
原始クラスローダーによって返されたクラスを仮想マシンに渡すだけです。その時点から、クラスが。という名前のString
クラスをVolcano
参照するときはいつでも、仮想マシンはそのクラスを使用しString
ます。
サンドボックス内のクラスローダー
Javaのサンドボックスでは、クラスローダーアーキテクチャが悪意のあるコードに対する最初の防衛線です。結局のところ、コードをJVMに取り込むのはクラスローダーであり、敵対的な可能性のあるコードです。
クラスローダーアーキテクチャは、次の2つの方法でJavaのサンドボックスに貢献します。
- 悪意のあるコードが善意のコードに干渉するのを防ぎます。
- 信頼できるクラスライブラリの境界を保護します。
クラスローダーアーキテクチャは、信頼されていないクラスが信頼されているふりをしないようにすることで、信頼されているクラスライブラリの境界を保護します。悪意のあるクラスがJVMをだましてJavaAPIからの信頼できるクラスであると信じ込ませることができた場合、その悪意のあるクラスはサンドボックスの障壁を突破する可能性があります。信頼できないクラスが信頼できるクラスになりすますのを防ぐことにより、クラスローダーアーキテクチャは、Javaランタイムのセキュリティを危険にさらす可能性のある1つのアプローチをブロックします。
名前空間とシールド
クラスローダーアーキテクチャは、さまざまなクラスローダーによってロードされるクラスに保護された名前空間を提供することにより、悪意のあるコードが有益なコードに干渉するのを防ぎます。上記のように、名前空間は、JVMによって維持されるロードされたクラスの一意の名前のセットです。
名前空間は、実際には、異なる名前空間にロードされたクラス間にシールドを配置できるため、セキュリティに貢献します。JVM内では、同じ名前空間内のクラスが相互に直接対話できます。ただし、異なる名前空間のクラスは、クラスの相互作用を可能にするメカニズムを明示的に提供しない限り、互いの存在を検出することさえできません。悪意のあるクラスがロードされると、仮想マシンによって現在ロードされている他のすべてのクラスへのアクセスが保証されている場合、そのクラスは、知らないはずのことを学習したり、プログラムの適切な実行を妨害したりする可能性があります。
安全な環境の作成
クラスローダーを使用するアプリケーションを作成するときは、動的にロードされるコードが実行される環境を作成します。環境にセキュリティホールがないようにする場合は、アプリケーションとクラスローダーを作成するときに特定のルールに従う必要があります。一般に、悪意のあるコードが善意のコードから保護されるように、アプリケーションを作成することをお勧めします。また、Java APIなどの信頼できるクラスライブラリの境界を保護するように、クラスローダーを作成することもできます。
名前空間とコードソース
名前空間によって提供されるセキュリティ上の利点を得るには、さまざまなソースからさまざまなクラスローダーを介してクラスをロードする必要があります。これは、Java対応のWebブラウザで使用される上記のスキームです。Webブラウザによって起動されたJavaアプリケーションは、通常、ネットワークを介してダウンロードするクラスのソースごとに異なるアプレットクラスローダーオブジェクトを作成します。たとえば、ブラウザは1つのクラスローダーオブジェクトを使用して//www.niceapplets.comからクラスをダウンロードし、別のクラスローダーオブジェクトを使用して//www.meanapplets.comからクラスをダウンロードします。
制限されたパッケージの保護
Javaでは、同じパッケージ内のクラスが、パッケージ外のクラスには付与されていない特別なアクセス権限を相互に付与できます。したがって、クラスローダーがJava APIの一部であると勇敢に宣言するクラス(たとえば、という名前のクラスjava.lang.Virus
)をロードする要求を受け取った場合、クラスローダーは慎重に進める必要があります。ロードされると、そのようなクラスはの信頼されたクラスへの特別なアクセスを取得し、java.lang
その特別なアクセスを不正な目的に使用する可能性があります。
したがって、通常は、Java API(またはその他の信頼できるランタイムライブラリ)の一部であると主張しているが、ローカルの信頼できるリポジトリには存在しないクラスのロードを単に拒否するように、クラスローダーを作成します。つまり、クラスローダーが要求をプリミティブクラスローダーに渡し、プリミティブクラスローダーがクラスをロードできないことを示した後、クラスローダーはクラスが自分自身をメンバーとして宣言していないことを確認する必要があります。信頼できるパッケージの。含まれている場合、クラスローダーは、ネットワーク経由でクラスをダウンロードしようとする代わりに、セキュリティ例外をスローする必要があります。
禁止されているパッケージの保護
さらに、アプリケーションが基本クラスローダーを介してロードできるようにしたいが、クラスローダーを介してロードされたクラスにアクセスしたくないクラスを含むいくつかのパッケージを信頼できるリポジトリにインストールした可能性があります。たとえば、名前が付けられたパッケージを作成し、absolutepower
それを基本クラスローダーがアクセスできるローカルリポジトリにインストールしたとします。また、クラスローダーによってロードされたクラスがabsolutepower
パッケージから任意のクラスをロードできないようにする必要があると想定します。この場合、最初に行うことは、要求されたクラスが自分自身をメンバーとして宣言しないようにすることであるように、クラスローダーを記述します。absolutepower
パッケージ。このようなクラスが要求された場合、クラス名を基本クラスローダーに渡すのではなく、クラスローダーがセキュリティ例外をスローする必要があります。
クラスローダーが、クラスがなどの制限されたパッケージからのものか、などjava.lang
の禁止されたパッケージからのものかを知る唯一の方法は、クラスabsolutepower
の名前によるものです。したがって、クラスローダーには、制限されたパッケージと禁止されたパッケージの名前のリストを指定する必要があります。クラスの名前java.lang.Virus
はそれがjava.lang
パッケージからのものでありjava.lang
、制限されたパッケージのリストにあることを示しているため、原始クラスローダーがそれをロードできない場合、クラスローダーはセキュリティ例外をスローする必要があります。同様に、クラスの名前absolutepower.FancyClassLoader
はそれがabsolutepower
パッケージの一部であることを示しており、absolutepower
パッケージは禁止パッケージのリストに含まれているため、クラスローダーはセキュリティ例外をスローする必要があります。
セキュリティ志向のクラスローダー
セキュリティ志向のクラスローダーを作成する一般的な方法は、次の4つの手順を使用することです。
このクラスローダーがロードを許可されていないパッケージが存在する場合、クラスローダーは、要求されたクラスが上記の禁止されたパッケージの1つに含まれているかどうかを確認します。その場合、セキュリティ例外がスローされます。そうでない場合は、ステップ2に進みます。
クラスローダーは、要求を基本クラスローダーに渡します。原始クラスローダーがクラスを正常に返すと、クラスローダーは同じクラスを返します。それ以外の場合は、ステップ3に進みます。
このクラスローダーがクラスの追加を許可されていない信頼できるパッケージが存在する場合、クラスローダーは、要求されたクラスがそれらの制限されたパッケージの1つにあるかどうかを確認します。その場合、セキュリティ例外がスローされます。そうでない場合は、ステップ4に進みます。
- 最後に、クラスローダーは、ネットワークを介してクラスをダウンロードするなど、カスタムの方法でクラスをロードしようとします。成功すると、クラスを返します。失敗すると、「クラス定義が見つかりません」というエラーがスローされます。
上記の手順1と3を実行することにより、クラスローダーは信頼できるパッケージの境界を保護します。ステップ1では、禁止されているパッケージのクラスがロードされるのを防ぎます。ステップ3では、信頼できないクラスが自分自身を信頼できるパッケージに挿入することを許可しません。
結論
クラスローダーアーキテクチャは、次の2つの方法でJVMのセキュリティモデルに貢献します。
- コードを複数の名前空間に分割し、異なる名前空間のコード間に「シールド」を配置する
- JavaAPIなどの信頼できるクラスライブラリの境界を保護する
Javaのクラスローダーアーキテクチャのこれらの機能は両方とも、プログラマが提供するセキュリティ上の利点を享受するために、プログラマが適切に使用する必要があります。名前空間シールドを利用するには、さまざまなソースからのコードをさまざまなクラスローダーオブジェクトを介してロードする必要があります。信頼できるパッケージの境界保護を利用するには、クラスローダーを作成して、要求されたクラスの名前を制限付きおよび禁止されているパッケージのリストと照合する必要があります。
サンプルコードを含むクラスローダーを作成するプロセスのウォークスルーについては、ChuckMcManisのJavaWorldの記事「Javaクラスローダーの基本」を参照してください。
来月
来月の記事では、クラスベリファイアについて説明することにより、JVMのセキュリティモデルの説明を続けます。
Bill Vennersは、12年間専門的にソフトウェアを作成してきました。シリコンバレーを拠点とし、Artima SoftwareCompanyという名前でソフトウェアコンサルティングおよびトレーニングサービスを提供しています。長年にわたり、彼は家電、教育、半導体、生命保険業界向けのソフトウェアを開発してきました。彼は多くのプラットフォームで多くの言語でプログラミングを行ってきました。さまざまなマイクロプロセッサのアセンブリ言語、UnixのC、WindowsのC ++、WebのJavaです。彼は、McGraw-Hillから出版された本「InsidetheJavaVirtualMachine」の著者です。このトピックの詳細
- ブックザ・Java仮想マシン仕様(//www.aw.com/cp/lindholm-yellin.html)、ティム・リンドホルム及びフランク・イェリンによって(ISBN 0-201-63452-X)、Javaのシリーズの一部(// Addison-Wesleyのwww.aw.com/cp/javaseries.html)は、最も信頼のおけるJava仮想マシンリファレンスです。
- JavaNowと未来を備えたセキュアコンピューティング(ホワイトペーパー)// www.javasoft.com/marketing/collateral/security.html
- アプレットのセキュリティに関するFAQ
//www.javasoft.com/sfaq/
- Javaの低レベルセキュリティ、 FrankYellin著//www.javasoft.com/sfaq/verifier.html
- Javaセキュリティホームページ
//www.javasoft.com/security/
- 敵対的なアプレットのホームページを参照してください
//www.math.gatech.edu/~mladue/HostileApplets.html
- GaryMcGraw博士とEdFeltonによる本JavaSecurityHostile Applets、Holes、and Antidotesは、 Javaを取り巻くセキュリティ問題の徹底的な分析を提供します。//www.rstcorp.com/java-security.html
- 以前の「UnderTheHood」の記事:
- リーンで平均的な仮想マシン-Java仮想マシンの概要を説明します。
- Javaクラスファイルのライフスタイル-すべてのJavaプログラムがコンパイルされるファイル形式であるJavaクラスファイルの概要を示します。
- Javaのガベージコレクションヒープ-一般的なガベージコレクション、特にJava仮想マシンのガベージコレクションヒープの概要を説明します。
- バイトコードの基本-Java仮想マシンのバイトコードを紹介し、特にプリミティブ型、変換操作、およびスタック操作について説明します。
- 浮動小数点演算-Java仮想マシンの浮動小数点サポートと浮動小数点演算を実行するバイトコードについて説明します。
- 論理と算術-Java仮想マシンの論理演算と整数演算のサポート、および関連するバイトコードについて説明します。
- オブジェクトと配列-Java仮想マシンがオブジェクトと配列を処理する方法を説明し、関連するバイトコードについて説明します。
- 例外-Java仮想マシンが例外を処理する方法を説明し、関連するバイトコードについて説明します。
- Try-Finally-Java仮想マシンがtry-finally句を実装する方法を説明し、関連するバイトコードについて説明します。
- 制御フロー-Java仮想マシンが制御フローを実装する方法を説明し、関連するバイトコードについて説明します。
- アグレットのアーキテクチャー-IBMの自律Javaベースのソフトウェアエージェントテクノロジーであるアグレットの内部動作について説明します。
- Agletsのポイント-IBMの自律型Javaベースのソフトウェアエージェントテクノロジーであるagletsなどのモバイルエージェントの実際のユーティリティを分析します。
- メソッドの呼び出しと戻り-関連するバイトコードを含む、Java仮想マシンがメソッドを呼び出す4つの方法について説明します。
- スレッド同期-Java仮想マシンでスレッド同期がどのように機能するかを示します。モニターに出入りするためのバイトコードについて説明します。
- Javaのセキュリティアーキテクチャ-JVMに組み込まれているセキュリティモデルの概要を説明し、JVMに組み込まれている安全機能について説明します。
このストーリー「セキュリティとクラスローダーアーキテクチャ」は、もともとJavaWorldによって公開されました。