リフレクション出力のセキュリティ関連事項
更新 : 2007 年 11 月
.NET Framework には、Microsoft Intermediate Language (MSIL) を出力する方法が 3 種類ありますが、それぞれに固有のセキュリティ問題があります。
動的アセンブリ
匿名でホストされる動的メソッド
既存のアセンブリに関連付けられた動的メソッド
動的コードの生成方法に関係なく、生成済みコードを実行するには、生成済みコードで使用される型やメソッドに必要なすべてのアクセス許可が必要です。
メモ : |
---|
コードでのリフレクションとコードの出力に必要なアクセス許可は、.NET Framework のバージョンによって異なります。このトピックの「バージョン情報」を参照してください。 |
動的アセンブリ
動的アセンブリを作成するには、AppDomain.DefineDynamicAssembly メソッドのオーバーロードを使用します。必要なアクセス許可は、使用するオーバーロードによって決まります。たとえば、証拠を生成するオーバーロードの場合、SecurityPermission に SecurityPermissionFlag.ControlEvidence フラグを指定する必要があります。アクセス許可が不要で、インターネット アクセス許可しか付与されていないコードからも呼び出せるオーバーロードもあります。
動的アセンブリのコードからは、参照できる型と他のアセンブリのメンバのみにアクセスできます。
メモ : |
---|
動的アセンブリでは、動的メソッドが非パブリックな型とメンバにアクセスすることを許可する ReflectionPermissionFlag.MemberAccess フラグと ReflectionPermissionFlag.RestrictedMemberAccess フラグが使用されません。 |
デバッグ シンボルを使ってコードを生成するには、ReflectionPermission に ReflectionPermissionFlag.ReflectionEmit フラグを指定する必要があります。
一時動的アセンブリはメモリ内に作成され、ディスクに保存されることがないため、ファイルへのアクセス許可は不要です。動的アセンブリをディスクに保存するには、FileIOPermission に適切なフラグを指定する必要があります。
部分信頼コードからの動的アセンブリの生成
インターネット アクセス許可が設定されたアセンブリで一時動的アセンブリを生成し、そのコードを実行するための条件を考えてみましょう。
動的アセンブリで使用されるのが、パブリック型と他のアセンブリのメンバのみである。
その型およびメンバで必要なアクセス許可が、部分信頼のアセンブリの許可セットに含まれている。
動的アセンブリの作成に使用される DefineDynamicAssembly メソッド オーバーロードに特別なアクセス許可が必要ない (つまり、証拠が用意されていないなど)。
アセンブリがディスクに保存されていない。
デバッグ シンボルが生成されていない (Internet および LocalIntranet のアクセス許可セットに ReflectionPermissionFlag.ReflectionEmit フラグが指定されていない)。
動的アセンブリのアクセス許可の確立
次の一覧で、"エミッタ" とは動的アセンブリを作成するアセンブリを指します。
SecurityPermission に SecurityPermissionFlag.ControlEvidence フラグが指定されたエミッタにより、生成されるコード用の証拠を提供できます。付与されているアクセス許可を判断するため、この証拠がポリシーに割り当てられます。
エミッタでは null の証拠を提供できます。この場合、アセンブリでは、エミッタのアクセス許可セットが取得されます。これにより、生成されるコードにはこのエミッタのアクセス許可よりも上位のアクセス許可が含まれません。
SecurityAction.RequestMinimum、SecurityAction.RequestOptional、または SecurityAction.RequestRefuse を指定したアクセス許可セットを用意した場合は、アセンブリがディスクに保存された後、ディスクから読み込まれるまで、このアクセス許可セットは使用されません。
動的アセンブリは、ディスクに保存された後は、ディスクから読み込まれる他のアセンブリと同様の方法で操作されます。
部分的に信頼度の高いエミッタによって生成されたコードは常に検査されます。特にランタイムでは、SecurityPermission に SecurityPermissionFlag.SkipVerification フラグが指定されていないコードは常に検査されます。完全に信頼されているエミッタは、検査を省略する場合と、生成コードの検査を必要とする場合があります。
匿名でホストされる動的メソッド
関連付けられる型やモジュールを指定しない 2 つの DynamicMethod コンストラクタ (DynamicMethod(String, Type, array<Type[]) および DynamicMethod(String, Type, array<Type[], Boolean)) を使用して、匿名でホストされる動的メソッドを作成します。このコンストラクタにより、システムで指定された完全に信頼される透過的セキュリティ アセンブリに動的メソッドが置かれます。このコンストラクタの使用や動的メソッドのコード出力のために、特別なアクセス許可は必要ありません。
ただし、匿名でホストされる動的メソッドが作成されるとき、コール スタックがキャプチャされます。メソッドの作成時に、キャプチャされたコール スタックに対してセキュリティ要求が行われます。
メモ : |
---|
概念的には、メソッドの作成中に要求が行われます。つまり、MSIL 命令が生成されるたびに要求を実行できます。現在の実装では、DynamicMethod.CreateDelegate メソッドが呼び出されたとき (CreateDelegate を呼び出さずにこのメソッドが呼び出される場合)、または Just-In-Time (JIT) コンパイラが呼び出されたときに、すべての要求が行われます。 |
匿名でホストされる動的メソッドでは、JIT の参照範囲チェックを省略できますが、制限があります。匿名でホストされる動的メソッドによりアクセスされる非パブリックの型とメンバがアセンブリに含まれ、そのアセンブリの許可セットが、出力元のコール スタックの許可セットに等しいか、そのサブセットであることが必要です。この制限付き機能を使って JIT 参照範囲チェックを省略するには、ReflectionPermission に ReflectionPermissionFlag.RestrictedMemberAccess フラグを指定する必要があります。
メソッドでパブリックな型とメンバのみを使用する場合は、作成中にアクセス許可は不要です。
JIT 参照範囲チェックを省略するように指定した場合、メソッドの作成時に行われる要求には ReflectionPermissionFlag.RestrictedMemberAccess フラグが指定された ReflectionPermission と、アクセスされる非パブリック メンバを含むアセンブリの許可セットが含まれます。
非パブリック メンバの許可セットが考慮されるため、ReflectionPermissionFlag.RestrictedMemberAccess によって許可された部分信頼コードでは、信頼されるアセンブリの非パブリック メンバを実行しても特権を昇格することができません。
通常の出力済みコードと同様に、動的メソッドを実行するには、動的メソッドで使用されるメソッドで必要なアクセス許可がすべて必要になります。
詳細については、DynamicMethod クラスを参照してください。
部分的に信頼されるコードによる匿名でホストされる動的メソッドの生成
インターネット アクセス許可が設定されたアセンブリで、匿名でホストされる動的メソッドを生成し、それを実行するための条件を考えてみましょう。
動的メソッドで使用されるのが、パブリックな型とメンバのみである。許可セットに ReflectionPermissionFlag.RestrictedMemberAccess が含まれる場合、使用できる非パブリックの型とメンバの許可セットは、出力元アセンブリの許可セットと同じか、またはそのサブセットになります。
動的メソッドで使用されるすべての型およびメンバで必要なアクセス許可が、部分信頼のアセンブリの許可セットに含まれている。
メモ : |
---|
動的メソッドではデバッグ シンボルがサポートされていません。 |
既存のアセンブリに関連付けられた動的メソッド
動的メソッドに既存アセンブリの型またはモジュールを関連付けるには、関連付ける型またはモジュールを指定する DynamicMethod コンストラクタのどれかを使用します。動的メソッドに既存の型またはモジュールを関連付けると、動的メソッドが非パブリックの型とメンバにアクセスできるようになるため、これらのコンストラクタを呼び出すにはアクセス許可が必要です。
型に関連付けられる動的メソッドは、その型のすべてのメンバ (プライベート メンバを含む) にアクセスでき、関連付けられた型が含まれるアセンブリ内部のすべての型およびメンバにアクセスできます。
モジュールに関連付けられる動的メソッドは、モジュールのすべての internal 型およびメンバ (Visual Basic では Friend、共通言語ランタイムのメタデータでは assembly) にアクセスできます。
さらに、JIT コンパイラの参照範囲チェックを省略する機能を指定するコンストラクタを使用できます。これを使用した場合、アクセス レベルに関係なく、動的メソッドからすべてのアセンブリのすべての型およびメンバにアクセスできます。
コンストラクタで必要なアクセス許可は、動的メソッドに与えるアクセス許可のレベルに応じて決まります。
メソッドでパブリックな型とメンバのみを使用し、それに独自の型や独自のモジュールを関連付ける場合は、アクセス許可が不要です。
JIT 参照範囲チェックを省略するように指定する場合、コンストラクタでは ReflectionPermission に ReflectionPermissionFlag.MemberAccess フラグを指定する必要があります。
動的メソッドに別の型を関連付ける場合 (独自に作成したアセンブリ内の別の型でも)、コンストラクタでは ReflectionPermission に ReflectionPermissionFlag.MemberAccess フラグを指定し、SecurityPermission に SecurityPermissionFlag.ControlEvidence フラグを指定する必要があります。
動的メソッドに別のアセンブリの型またはモジュールを関連付ける場合、コンストラクタでは 2 つの操作が必要です。それは、ReflectionPermission に ReflectionPermissionFlag.RestrictedMemberAccess フラグを指定することと、他のモジュールを含むアセンブリの許可セットを用意することです。つまり、対象のモジュールの許可セットにあるすべてのアクセス許可に加えて、ReflectionPermissionFlag.RestrictedMemberAccess がコール スタックに含まれる必要があります。
メモ : 下位互換性を確保するために、対象の許可セットと ReflectionPermissionFlag.RestrictedMemberAccess の両方の要件が満たされなかった場合、コンストラクタでは SecurityPermission に SecurityPermissionFlag.ControlEvidence フラグを指定する必要があります。
この一覧の項目は出力アセンブリの許可セットの観点から書かれていますが、要求はコール スタック全体 (アプリケーション ドメイン境界を含む) に対して行われることに注意してください。
詳細については、DynamicMethod クラスを参照してください。
部分信頼コードからの動的メソッドの生成
メモ : |
---|
部分的に信頼されるコードから動的メソッドを生成する方法として推奨されるのは、匿名でホストされる動的メソッドを使用する方法です。 |
インターネット アクセス許可が設定されたアセンブリで、動的メソッドを生成し、それを実行するための条件を考えてみましょう。
動的メソッドにそれを出力するモジュールまたは型が関連付けられているか、その許可セットに ReflectionPermissionFlag.RestrictedMemberAccess が含まれている。さらに、関連付けられているモジュールが含まれているアセンブリの許可セットが出力アセンブリの許可セットと等しいか、そのサブセットである。
動的メソッドで使用されるのが、パブリックな型とメンバのみである。許可セットに ReflectionPermissionFlag.RestrictedMemberAccess が含まれ、関連付けられているモジュールが含まれているアセンブリの許可セットが出力アセンブリの許可セットと等しいか、そのサブセットである場合、internal と指定されている (Visual Basic では Friend、共通言語ランタイム メタデータでは assembly) 型とメンバを使用できます。
動的メソッドで使用されるすべての型およびメンバで必要なアクセス許可が、部分信頼のアセンブリの許可セットに含まれている。
動的メソッドで JIT 参照範囲チェックを省略しない。
メモ : |
---|
動的メソッドではデバッグ シンボルがサポートされていません。 |
バージョン情報
.NET Framework version 2.0 Service Pack 1 以降では、動的アセンブリと動的メソッドを出力する際に、ReflectionPermission に ReflectionPermissionFlag.ReflectionEmit フラグを指定する必要がなくなりました。このフラグは、それ以前のすべてのバージョンの .NET Framework では必要となります。
メモ : |
---|
FullTrust および LocalIntranet の名前付きアクセス許可セットでは、既定で ReflectionPermission に ReflectionPermissionFlag.ReflectionEmit フラグが指定されますが、Internet アクセス許可セットでは指定されません。そのため、以前のバージョンの .NET Framework では、ReflectionEmit に対して Assert を実行する場合にのみ、インターネット アクセス許可でライブラリを使用できます。このようなライブラリでは、コーディング エラーがあるとセキュリティ ホールが発生するおそれがあるため、セキュリティを慎重に確認する必要があります。コードの生成は本質的に特権を必要とする操作ではないため、.NET Framework 2.0 SP1 はセキュリティ確認要求を発行せずに部分信頼シナリオでコードを出力できます。これは、生成されたコードには、コードを出力したアセンブリと同等以下のアクセス許可しかないことを意味します。これにより、コードを出力するライブラリは透過的セキュリティになるため、ReflectionEmit を要求する必要がなくなります。そのため、安全なライブラリを簡単に作成できるようになります。 |
さらに、.NET Framework 2.0 SP1 では部分的に信頼される動的メソッドの非パブリックの型およびメンバにアクセスできるように、ReflectionPermissionFlag.RestrictedMemberAccess フラグが導入されています。以前のバージョンの .NET Framework では、動的メソッドで非パブリックの型およびメンバにアクセスするには ReflectionPermissionFlag.MemberAccess フラグが必要でした。これは、部分信頼のコードには付与されないアクセス許可です。
最終的に、.NET Framework 2.0 SP1 では、匿名でホストされるメソッドが導入されました。
この機能を使用するには、アプリケーションで .NET Framework version 3.5 を対象とする必要があります。詳細については、「.NET Framework 3.5 のアーキテクチャ」を参照してください。
型およびメンバの情報の取得
.NET Framework 2.0 以降から、非パブリックな型とメンバに関する情報を取得する際にアクセス許可は不要になりました。動的メソッドを出力するために必要な情報を取得するには、リフレクションを使用します。たとえば、MethodInfo オブジェクトを使用してメソッド呼び出しを出力します。以前のバージョンの .NET Framework では、ReflectionPermission に ReflectionPermissionFlag.TypeInformation フラグを指定する必要があります。詳細については、「リフレクションに関するセキュリティ上の考慮事項」を参照してください。