CLR 徹底解剖

.NET Framework 4 のセキュリティ モデルの詳細

Andrew Dai

.NET Framework 4 では、サービスのホスト、セキュリティ強化、および部分的に信頼されたコードへの提供を容易にする変更など、.NET セキュリティ モデルにさまざまな変更が施されています。複雑だったコード アクセス セキュリティ (CAS) ポリシー システムが徹底的に見直されています。これまでの CAS ポリシー システムは強力でしたが、使いにくく、ましてや適切に使用することは困難でした。セキュリティ透過性モデルも機能強化され、セキュリティ適用に関する Silverlight での機能強化 (これについては、昨年 10 月の msdn.microsoft.com/ja-jp/magazine/cc765416.aspx を参照) の多くがデスクトップ フレームワークに移植されています。また、ホスト開発者やライブラリ開発者がサービスを公開する対象をより柔軟に制御できる新機能も導入しています。これらの変更のおかげで .NET Framework 4 のセキュリティ モデルはより簡潔で機能的になり、ホストおよびライブラリがコードやライブラリをサンドボックス化しやすくなり、安全にサービスを公開できるようになりました。

.NET Framework のセキュリティの背景

特定の機能について詳しく説明する前に、.NET Framework のセキュリティのしくみについての背景を少し知っておくと便利です。部分的に信頼されたコードは、そのコードのアクセス許可によって制限されます。また、API が問題なく呼び出されるには、API ごとに異なるアクセス許可が必要です。CAS の目標は、信頼されていないコードが適切なアクセス許可の下で実行され、権限なしにそのアクセス許可以上の操作を実行できないようにすることです。

.NET セキュリティ モデルは、3 つの要素から構成されると考えられます。それぞれの要素に特定の機能強化が施されているため、ここからは、この 3 つの基本要素に沿って説明していきます。

  • ポリシー—セキュリティ ポリシーは、特定の信頼されていないアセンブリまたはアプリケーションに付与するアクセス許可を定義します。マネージ コードには、コードがどこから読み込まれたかや、だれから発行されたかなどの情報を示す証拠オブジェクトが関連付けられています。この証拠を使用して、適切なアクセス許可を特定できます。この特定されたアクセス許可をアクセス許可セットと呼びます。.NET Framework では従来、このアクセス許可のコンピューター レベルの制御メカニズムとして、CAS ポリシーが使用されてきました。前述のとおり、ホストがそれぞれのセキュリティ ポリシーをより柔軟に制御できるようにし、ホストされていないコードでもネイティブ コードと同等の機能を実行できるように、CAS ポリシーが徹底的に見直されました。
  • サンドボックス—サンドボックスは、アセンブリまたはアプリケーションを特定のアクセス許可セットに制限する実際のプロセスです。推奨されるサンドボックス化の方法は、読み込まれるアプリケーションに割り当てるアクセス許可セットを用意したサンドボックス アプリケーション ドメインを作成し、特定のライブラリ アセンブリ (完全信頼のアセンブリ) の例外リストを作成することです。CAS ポリシーが廃止されることで、.NET Framework 4 では、部分的に信頼されるコードは常にこの方法でサンドボックス化されます。
  • 適用—適用とは、信頼されていないコードをそのサンドボックスに制限するメカニズムです。適用 API を適切に使用することで、信頼されていないアセンブリが、より信頼されている別のアセンブリの API を簡単に呼び出すというかたちで、実際のアクセス許可以上の操作が実行されることを防止できます。また、ホスト開発者やライブラリ開発者は、部分的に信頼されたコードによる昇格された動作へのアクセスを制御および制限して、意味のあるサービスを提供できます。レベル 2 のセキュリティ透過性モデルは、これまでより格段に簡単かつ安全に、この処理を実現できるようにしています。

.NET セキュリティ モデルは、ホスト開発者とライブラリ開発者 (両者は連携して作業することが多い) により特に重要視されてきました。.NET セキュリティ モデルの例としては ASP.NET と SQL CLR が挙げられます。どちらも、管理された環境内の制限されたコンテキストで、マネージ コードをホストします。このようなホストが部分的に信頼されたアセンブリを読み込む場合、適切なアクセス許可セットを使用してサンドボックス アプリケーション ドメインを作成します。アセンブリは、このサンドボックス ドメインに読み込まれます。またホストは、完全に信頼された、しかしホスト コードからしか呼び出せないライブラリ API も提供します。このライブラリもサンドボックス ドメインに読み込まれますが、前述の例外リストに明示的に追加されます。これらは .NET Framework の適用メカニズムを利用して、昇格された機能へのアクセスが厳しく制御されるようにします。

ほとんどのマネージ アプリケーション開発者にとって、これがフレームワーク レベルで処理されるというのはまったく魔法のようです。サンドボックスで実行されるコードを作成する開発者でさえ、セキュリティ モデルのしくみを事細かに知る必要はないのですから。サンドボックス化されたコードは、ホストが提供する API と機能しか使用できないように、フレームワークによって制限されます。.NET セキュリティ モデルと CAS は長年、エンタープライズ管理者とホストおよびライブラリの開発者の活動の場であると言えます。エンタープライズ管理者とホストおよびライブラリの開発者の方々に、かつてないほど簡単に作業していただけるようにしました。

ポリシー

CAS ポリシーは、ランタイムが何を信頼し、何を信頼しないと見なすかを、コンピューターおよびエンタープライズ管理者が調整できる手段として、.NET Framework の初期リリースから提供されています。CAS ポリシーは非常に強力で、非常に細かい制御が可能ですが、適切に使用することがきわめて難しく、役立つよりも邪魔になりかねませんでした。コンピューター管理者は、特定のアプリケーションから必要なアクセス許可を除外する場合があり (次の「サンドボックス化」で説明します)、アプリケーションをネットワーク共有に移動すると、アプリケーションが突然機能しなくなることを、多くのユーザーが不思議に思っていました。さらに、CAS ポリシー設定は古いバージョンから新しいバージョンに引き継がれないため、.NET Framework 1.1 で作成された手の込んだカスタム CAS ポリシーを .NET Framework 2.0 で使用するには、手作業で作成し直す必要がありました。

セキュリティ ポリシーは、ホスト対象のコード用のセキュリティ ポリシーと、コンピューターまたはエンタープライズ用のセキュリティ ポリシーの 2 つのシナリオに分けることができます。コンピューター ポリシーについて、共通言語ランタイム セキュリティ チームは、コンピューター ポリシーを制御する場所として、ランタイムは適切でないと判断しました。これは、ネイティブ コードが明らかにその制限対象にならないためです。ホスト自体がホスト対象のコードの動作を決定できることは理にかなっていますが、単にクリックされるかコマンド ラインから実行される、ホスト対象ではない実行可能ファイルは、それぞれのネイティブ環境に従って動作すべきです (特に、実行可能ファイルを実行しているユーザーにとっては見分けが付かないため)。

グローバル セキュリティ ポリシーを扱う適切なレベルは、オペレーティング システムです。オペレーティング システムであれば、このようなポリシーはネイティブ コードにもマネージ コードにも等しく適用されます。したがって、コンピューター管理者の方には、Windows のソフトウェアの制限ポリシー (SRP) などのソリューションを検討することをお勧めし、CAS ポリシーによるコンピューター レベルの解決は既定では無効にしました。もう一方のシナリオであるホスト対象のコード用のセキュリティ ポリシーは、マネージ コードの世界では現在でも非常に有効です。ホスト セキュリティ ポリシーは、任意のコンピューター ポリシーとの競合がなくなるため、制御しやすくなりました。

変更による具体的な影響

1 つは、ホスト対象ではないマネージ コードはすべて、既定では完全信頼のコードとして実行されます。.EXE をハード ドライブから実行してもネットワーク共有から実行しても、そのアプリケーションは、同じ場所から実行されたネイティブ アプリケーションと同じ機能をすべて利用できます。しかし、ホスト対象のコードには、この場合もホストのセキュリティ ポリシーが適用されます (ClickOnce アプリケーションなど、インターネット経由でコードが提供される方法はすべて、ホスト シナリオです。したがって、そのようなコードがインターネット上で完全信頼のコードとして実行されることはありません)。

多くのアプリケーションにとって、上記の変更はほとんどバックグラウンドでの変更であり、目に見える影響はありません。変更によって影響を受ける場合、2 つの問題が発生する可能性があります。1 つは、特定の CAS ポリシー関連 API が廃止される場合で、これは多くの場合アセンブリの読み込みに関係しています (アセンブリ読み込みを行う場合は、続きをお読みください)。もう 1 つは、影響を受けるユーザー (主にホスト) は少なくなりますが、既定では異種アプリケーション ドメイン (これについては「サンドボックス化」で説明します) を利用できないことです。

上記に該当せず、とにかく機能するようにしたい場合

次のようなエラー メッセージまたは廃止を示すメッセージが表示されたと思います。

「このメソッドが [明示的/暗黙的に] 使用する CAS ポリシーは、.NET Framework では使用されなくなっています。互換性のため CAS ポリシーを有効にするには、NetFx40_LegacySecurityPolicy 構成スイッチを使用してください。詳細については、[MSDN ドキュメントへのリンク] を参照してください。」

互換性のために、プロセスが CAS ポリシー解決を有効にできるようにする構成スイッチを用意しています。プロジェクトの app.config ファイルに次のコードを追加することで、CAS ポリシーを有効にすることができます。

<configuration>
   <runtime>
      <!-- enables legacy CAS policy for this process -->
      <NetFx40_LegacySecurityPolicy enabled="true" />
   </runtime>
</configuration>

次に、作成したコードから例外がスローされる場合、どのあたりから移行を検討すべきかについて説明します。例外がスローされない場合は、上記の構成スイッチを使用してください。このような場合、次の説明は直接関係しません。

影響を受ける API

影響を受ける API は、CAS ポリシーを明示的に使用するものと、暗黙に使用するものの 2 種類に分類できます。明示的に使用するものはすぐにわかります。System.Security.Policy.SecurityManager クラスに含まれている場合が多く、SecurityManager.ResolvePolicy のような API です。これらの API は、直接コンピューターの CAS ポリシー設定を呼び出すか変更するため、すべて使用できなくなります。

暗黙に使用するものはややわかりにくく、多くの場合、証拠を使用するアセンブリ読み込みかアプリケーション ドメインの作成が該当します。この証拠を基に CAS ポリシーが解決され、解決されたアクセス許可セットを使用して、アセンブリが読み込まれます。CAS ポリシーは既定では無効なため、証拠側で CAS ポリシーを解決することは意味がありません。このような API の例としては、Assembly.Load(AssemblyName assemblyRef,Evidence assemblySecurity) があります。

このような API が呼び出されるのには、次のような理由があります。

  1. サンドボックス化—おそらく、インターネットからゾーンの証拠によりオーバーロードされた Assembly.Load を呼び出すと、インターネットの名前付きアクセス許可セットを使用してアセンブリが読み込まれることをご存知だと思います (つまり、管理者がこの特定のコンピューターまたはユーザーに使用する証拠マッピングを変更していない限り)。
  2. オーバーロードのその他のパラメーター—単に、そののオーバーロードにのみ存在する特定のパラメーターにアクセスしたかっただけの場合。この場合は、単純に null または Assembly.GetExecutingAssembly().Evidence を目的の証拠のパラメーターに渡すことができたでしょう。

サンドボックス化を試みる場合は、インターネットの名前付きアクセス許可セットに制限される、サンドボックス アプリケーション ドメインを作成する方法を「サンドボックス化」で説明しています。このようなドメインを作成すると、そのドメインにアセンブリを読み込み、意図するアクセス許可を確実に適用できます (つまり、管理者の気まぐれに振り回されることがありません)。

2 つ目のシナリオでは、すべての必要なパラメーターは公開しても、証拠パラメーターは公開しないオーバーロードを該当する各 API に追加しています。移行処理は簡単で、呼び出しに渡している証拠の引数を取り除くことです (廃止される API に証拠として null 値を渡しても、CAS ポリシーの評価が行われないので、問題ありません)。

他に注意が必要なことは、アセンブリ読み込みをリモートから行う場合 (つまり、Assembly.LoadFrom(“http://...”))、次の構成スイッチが設定されていないと、最初は FileLoadException が返されます。これは、この呼び出しが以前であればアセンブリをサンドボックス化することになっていたためです。しかし、CAS ポリシーが廃止されたため、現在は完全信頼になりました。

<configuration>
   <runtime>
      <!-- WARNING: will load assemblies from remote locations as fully
         trusted! -->
      <loadFromRemoteSources enabled="true" />
   </runtime>
</configuration>

このスイッチをプロセス全体で有効にしないで、同じ効果を実現する別の方法は、新しい Assembly.UnsafeLoadFrom API を使用することです。この API は、このスイッチが設定された LoadFrom であるかのように動作します。これは、特定の場所でのリモート読み込みのみを有効にする場合や、プライマリ アプリケーションを所有していない場合に便利です。

コンピューター レベルの CAS ポリシーが廃止されたことで、アセンブリの証拠の検証と、適切なアクセス許可セットについての決定はすべて、マネージ コードのホストに一任されます。そのうえセキュリティの判断に干渉する複雑なシステムがなくなったことで (OS のセキュリティ ポリシーは除く)、ホストはホスト自体のアクセス許可を自由に割り当てることができます。では、このようなアクセス許可を部分信頼のアセンブリに割り当てましょう。

サンドボックス化

ホストのセキュリティ ポリシーによって、部分信頼のアセンブリに割り当てる正しいアクセス許可セットを特定できます。ここで、その特定のアクセス許可セットに制限する環境に、そのアセンブリを読み込むための簡単で有効な手段が必要になります。それには、サンドボックス、具体的には簡易サンドボックス化 CreateDomain オーバーロードを使用します。

以前のサンドボックス化

古い CAS ポリシー モデルでは、ドメイン内の各アセンブリが独自のアクセス許可セットを持つ異種アプリケーション ドメインを作成できました。インターネット ゾーンの証拠を使用したアセンブリ読み込みの結果、読み込みを行っている完全信頼アセンブリと同じドメインに、信頼レベルが異なる複数の部分信頼アセンブリが読み込まれる可能性がありました。さらに、そのアプリケーション ドメインには独自の証拠があり、独自のアクセス許可セットを割り当てている可能性もありました。

このモデルには、次のような問題があります。

  • アセンブリに割り当てられるアクセス許可セットは CAS ポリシーによって決まり、複数のポリシー レベルで共通部分が抜き出されて、最終的なアクセス許可セットが計算されます。したがって、意図したよりも少ないアクセス許可しか適用されない可能性があります。
  • 上記の点と同様に、アセンブリの証拠の評価は CAS ポリシーによって行われますが、このポリシーはコンピューター、ユーザー、さらには (CAS ポリシー設定はランタイムの新しいバージョンに継承されなかったため) ランタイムのバージョン間で異なる可能性がありますしたがって、どのようなアクセス許可セットがアセンブリに割り当てられるかが、確定していませんでした。
  • 部分信頼のアセンブリは、通常、セキュリティ強化のために検証されることはないため、"信頼レベルが中" のアセンブリが "信頼レベルが低" のアセンブリに利用される可能性がありました。アセンブリどうしを自由かつ簡単に呼び出すことができるため、セキュリティの観点では、機能の異なるこのようなアセンブリを多数用意することは問題になります。信頼レベルが異なるアセンブリからの呼び出しの組み合わせがすべて安全だと断言できる人はいるでしょうか。中レベルの信頼の層からの情報をキャッシュすることは、絶対に安全でしょうか。

このような問題のために、同種アプリケーション ドメインという概念を導入しました。このドメインには、2 種類のアクセス許可セット (部分信頼と完全信頼) しかなく、きわめてシンプルに作成および論理的な判断が可能でます。同種ドメインとその作成方法については、この後説明します。

サンドボックス化によく利用されたもう 1 つのメカニズムは PermitOnly と Deny というスタック ウォーク修飾子です。PermitOnly は特定の許可されたアクセス許可を列挙 (だけ) し、Deny は特定のアクセス許可を禁止します。「アクセス許可 x と y を持つ呼び出し元のみが、この API を呼び出せるようにする」とか、「API としては、すべての呼び出し元へのアクセス許可を拒否する」と言えると便利なように思えます。しかし、これらの修飾子は、実際には特定のアセンブリのアクセス許可セットを変更しません。つまり、これらの修飾子は要求をインターセプトしているだけなので、アサートされる可能性があります。図 1 は、この例を示しています。

図 1 Deny を使用してサンドボックス化を試みた場合の呼び出し履歴

赤字の Assert がなければ、要求は Deny を検出し、スタック ウォークは終了します。しかし、赤字の Assert が有効な場合、Untrusted が要求をアサートするため、Deny が検出されることはありません (注: この図の呼び出し履歴は、下方向に進んでいます。API は、.NET Framework の実際の API ではありません)。このため、Deny は .NET Framework 4 では廃止されました。これを使用すると常にセキュリティ ホールになるためです (PermitOnly は、いくつかまれな場合に正規で使用されることがあるため、バージョン 4 でも使用できますが、基本的には推奨されません)。なお、「ポリシー」で触れた NetFx40_LegacySecurityPolicy スイッチを使用すると、Deny を再び有効にすることができます。

現在のサンドボックス化

.NET Framework では、分離に使用する単位はアプリケーション ドメインです。各部分信頼アプリケーション ドメインには、1 つのアクセス許可セットしかなく、完全信頼除外リストで明示的に指定されているか、グローバル アセンブリ キャッシュから読み込まれたものを除き、そのドメインに読み込まれるすべてのアセンブリにそのセットが割り当てられます。このドメインは非常に簡単に作成できます。.NET Framework には簡易サンドボックス化 API があり、この API にドメインの作成に必要なものがすべて渡されます。

AppDomain.CreateDomain( string friendlyName,
 
                        Evidence securityInfo,
                        
                        AppDomainSetup info,
                        
                        PermissionSet grantSet,
                        
                        params StrongName[] fullTrustAssemblies);

各パラメーターの意味は、次のとおりです。

  • friendlyName—アプリケーション ドメインのフレンドリ名。
  • securityInfo—アプリケーション ドメインに関連付けられている証拠。これは言うまでもなく、CAS ポリシー解決には使用されませんが、発行元情報などを保持するために使用できます。
  • info—アプリケーション ドメインの初期化情報。これには少なくとも ApplicationBase を含める必要があります。ApplicationBase は、部分信頼アセンブリが保持されているストアを表します。
  • grantSet—完全信頼リストに指定されているか、グローバル アセンブリ キャッシュにあるものを除き、そのドメインに読み込まれるすべてのアセンブリに使用されるアクセス許可セット。
  • fullTrustAssemblies—完全信頼が付与される (部分信頼から除外される) アセンブリの StrongNames の一覧。

ドメインが作成されると、AppDomain.CreateInstanceAndUnwrap を部分信頼アセンブリの MarshalByRefObject に対して呼び出し、さらに、そのエントリ ポイント メソッドを呼び出して実行できます (図 2 参照)。

図 2 内部で部分信頼コードが実行されるサンドボックス

PermissionSet permset = new PermissionSet(PermissionState.None);
ps.AddPermission(new SecurityPermission(
   SecurityPermissionFlag.Execution));
AppDomainSetup ptInfo = new AppDomainSetup();
ptInfo.ApplicationBase = ptAssemblyStore;
 
AppDomain sandboxedDomain = AppDomain.CreateDomain(
   "Sandbox",
   AppDomain.CurrentDomain.Evidence,
   ptInfo,
   permset);
 
// assume HarnessType is in the GAC and a MarshalByRef object

HarnessType ht = sandboxedDomain.CreateInstanceAndUnwrap(
   typeof(HarnessType).Assembly.FullName,
   typeof(HarnessType).FullName)
   as HarnessType;
 
ht.LoadPTEntryPoint();

これだけです。数行のコードで、部分信頼コードが実行されるサンドボックスを作成できました。

この CreateDomain API は、実は .NET Framework 2.0 で追加されているので、新しいものではありません。ただし、現在はこれがサンドボックス コードを本当にサポートする唯一の手段であるため、取り上げる価値がありました。ご覧のとおり、アクセス許可セットが直接渡されるため、このドメインにアセンブリが読み込まれるときに証拠を評価する必要がありません。読み込まれる各アセンブリにどのようなセットが割り当てられるかを、正確に把握できます。さらに、部分信頼コードを保持するための、正真正銘の分離境界を使用していることになり、これはセキュリティの状態を想定する場合に非常に役立ちます。簡易サンドボックス化 API の CreateDomain を使用することで、サンドボックスはよりわかりやすく、一貫性があり、安全なものになります。これらの特徴はどれも、信頼されないコードの処理を容易にするうえで役立ちます。

適用

この時点で、部分信頼アセンブリに割り当てる適切なアクセス許可セットが用意され、アセンブリが適切なサンドボックスに読み込まれています。すばらしいことです。しかし、実は、昇格された機能を部分信頼コードに公開する必要があるとしたらどうなるでしょうか。たとえば、インターネット アプリケーションにはファイル システムへの完全なアクセスを許可しなくても、既知の一時フォルダーからの読み取りや書き込みについては禁止しない場合などです。

昨年公開した Silverlight のセキュリティについてのコラム (msdn.microsoft.com/ja-jp/magazine/cc765416.aspx) をお読みになった方は、Silverlight ではどのようにこの問題に対応しているかを正確にご存知です。つまり、コードを巧みに 3 つのカテゴリに分けるセキュリティ透過性モデルを使用します。さいわい、その Silverlight でのモデルの強化が、.NET Framework 4 にも移植されています。つまり、Silverlight プラットフォーム ライブラリが利用しているこのシンプルなモデルの持つメリットを、マイクロソフト以外の部分信頼ライブラリの開発者も享受できるようになりました。ただし、この点と、適用上の他の機能強化について説明する前に、以前の主な適用メカニズムについて説明したいと思います。

以前の適用

昨年、セキュリティの透過性は実は .NET Framework 2.0 で導入されていましたが、適用のメカニズムではなく、主に監査メカニズムとして使用されていることに触れました (新しいセキュリティ透過性モデルは両方に使用されます)。古いモデル、つまりレベル 1 のセキュリティ透過性では、違反は処理を停止させるエラーとしては表現されず、その多く (ネイティブ コードに対する p/invoking など) はアクセス許可の要求を行うことになりました。透過性アセンブリのアクセス許可セットに、偶然にも UnmanagedCode が含まれていた場合、さらに処理 (プロセス内の透過性ルール違反) が続けられます。また、透過性チェックはアセンブリの境界で停止するため、適用の有効性はさらに低くなります。

.NET Framework 2.0 での本当の適用は LinkDemands の形で実現されました。LinkDemands は JIT 時チェックで、呼び出し元アセンブリの許可セットに特定のアクセス許可が含まれているかをチェックします。これで問題ありませんが、このモデルでは基本的にライブラリ開発者が監査と適用に 2 種類のメカニズムを使用する必要があり、冗長です。この 2 つの概念が統合、整理された Silverlight モデルは、この状態からの自然な進化であり、これが現在のレベル 2 のセキュリティ透過性になりました。

レベル 2 のセキュリティ透過性

レベル 2 のセキュリティ透過性は、信頼レベルが低い環境で実行しても安全なコードと、そうでないコードを分離する適用メカニズムです。つまり、ファイルの操作など、セキュリティ上の影響が大きい操作を実行できるコード (Critical) と、できないコード (Transparent) の間に境界を設けます。

セキュリティ透過性モデルは、コードを Transparent、Safe Critical、Critical の 3 つのカテゴリに分類します。次のダイアグラム (図 3) は、この 3 つのカテゴリを示しています (注: 緑の矢印は許可されている呼び出しを表し、赤の矢印は許可されていない呼び出しを表します。自己ループも有効ですが、この図には示されていません)。


図 3 セキュリティ透過性モデル

一般的なデスクトップ アプリケーションでは、レベル 2 の透過性モデルには、認識できる影響はありません。セキュリティの注釈がなくサンドボックス化されていないコードは Critical であると見なされるため、制限されません。ただし、Critical であるため、部分信頼呼び出し元からは呼び出しできません。したがって、部分信頼シナリオがない場合は、部分信頼に何かが公開されることを心配する必要がありません。

サンドボックス化アプリケーションの場合は、その逆が当てはまります。サンドボックス化されたアプリケーション ドメインに読み込まれるアセンブリはどのアセンブリも、(たとえ、それとは異なる指定の注釈が付いている場合でも) 完全に Transparent であると見なされます。これにより、部分信頼コードがアクセス許可をアサートするか、ネイティブ コードへの呼び出し (完全信頼と同等の操作) を行うことで昇格を試みられないようにします。

部分信頼呼び出し元に公開されるライブラリは、デスクトップまたはサンドボックス化アプリケーションと異なり、セキュリティ要件に十分に注意する必要があります。また、これらのライブラリでは、各ライブラリの機能と公開する内容をより柔軟に制御できます。部分信頼で呼び出し可能なライブラリは通常、基本的に、最低限の Safe Critical API のセットを持つ Transparent および Critical コードになります。Critical コードには制限がありませんが、部分信頼コードからはアクセスできないことが知られています。Transparent コードは、部分信頼コードから呼び出し可能ですが安全です。Safe Critical は、昇格機能を提供するため、非常に危険であり、細心の注意を払って、確実に Critical コードに遷移する前に呼び出し元が検証されるようにする必要があります。

セキュリティ透過性の属性とその動作を、図 4 に示します。制限が最も少ない属性では、API 自体に注釈が付けられているかどうかにかかわらず、その属性を使用して読み込まれたすべての API が対象になることに注意してください。AllowPartiallyTrustedCallers では、より低いレベルの属性が優先される点が異なります (注: この表では、属性と、アセンブリ、型、またはメンバー レベルで適用された場合の属性の動作を示しています。属性は読み込まれた API にのみ適用されます。つまり、サブクラスとオーバーライドは継承ルールに従うため、透過性レベルが異なる可能性があります)。

図 4 セキュリティ透過性の属性とその動作

昨年 10 月の記事を覚えていらっしゃる方は、おそらく、これらの属性が Silverlight との属性とほぼ同じように機能することに気付かれるでしょう。また、コードの種類に応じて特定の継承ルールがあったことも思い出されるかもしれません。これらのルールも、デスクトップ フレームワークに移植されています。継承ルールやレベル 2 の透過性のその他の特徴の詳細については、「Silverlight 2 のセキュリティ」(msdn.microsoft.com/ja-jp/magazine/cc765416.aspx) を参照してください。

条件付きの AllowPartiallyTrustedCallers

AllowPartiallyTrustedCallers 属性 (APTCA) は、アセンブリがセキュリティ上影響の大きい機能を部分信頼に対して公開する可能性があるライブラリであることを示します。APTCA ライブラリ アセンブリは、多くの場合、ホストと併せて作成されます。これは、ホストが通常、特定の機能をホスト環境に公開する必要があるためです。よく知られている例の 1 つは ASP.NET で、これは System.Web 名前空間をホスト対象のコードに公開します。このとき、信頼レベルは異なる可能性があります。

ただし、APTCA をアセンブリに適用したとしても、そのアセンブリを読み込むすべてのホストで、このアセンブリが部分信頼に公開されるとは限らないため、アセンブリの作成者が別のホストではそのアセンブリがどのように動作するかを把握していない場合、問題になる可能性があります。したがって、ホスト開発者は、開発者自身のドメインに読み込まれる場合にのみ、ライブラリを部分信頼に公開したい場合があります。ASP.NET はまさにこれを実現しますが、以前のバージョンでは LinkDemands を使用して API に特別なアクセス許可を設定する必要がありました。これでも機能しますが、これらを基盤に構築されるものはすべて、LinkDemand を満たさなければならず、上位のアセンブリは透過的になりません。

これを解決するために、条件付き APTCA 機能を導入しました。この機能を使用すると、有効なホスト (リストにより指定) 内でのみ、アセンブリは部分信頼呼び出し元に API を公開できます。

ホストとライブラリの具体的な役割は、次のとおりです。

  • ライブラリは単純に、パラメーターとして PartialTrustVisibilityLevel 列挙子を使用し、AllowPartiallyTrustedCallers 属性を修飾します。次に例を示します。
[assembly: AllowPartiallyTrustedCallers(PartialTrustVisibilityLevel= PartialTrustVisibilityLevel.NotVisibleByDefault)]
  • この属性は、基本的に、以下で説明するように、ライブラリがホストの許可リストに指定されていない限り、部分信頼からは呼び出せないことを示しています。値を VisibleToAllHosts にすると、すべてのホストで部分信頼からライブラリが呼び出せるようになります。

  • ホストは許可リストを利用して、アプリケーション ドメインごとに、部分信頼から認識できるアセンブリを指定します。このリストは、通常、ホストに提供される構成ファイルによって値が設定されます。注意する必要があるのは、基本のフレームワーク ライブラリなど、条件が設定されていない APTCA アセンブリは、このリストに追加する必要がないことです (また、条件付き APTCA アセンブリを有効にする場合、依存する条件付き APTCA アセンブリの推移的閉包も有効にした方がよいことにも注意してください。推移的閉包を有効にしないと、元のアセンブリから、実際にはアクセスできなくてもアクセスできると見なしている API を呼び出そうとするため、動作がおかしくなる可能性があります)。

セキュリティ保護を簡単に

.NET Framework 4 のセキュリティ モデルは、大幅に変更されています。CAS ポリシーが既定で無効になり、すべてのセキュリティ ポリシーの判断はホスト側で処理されるようになったほか、ホストされていないマネージ実行ファイルの動作は、ネイティブの実行ファイルの動作と同等になりました。CAS ポリシーを無効にすることで、異種アプリケーション ドメインも無効になり、ついに効率的な簡易サンドボックス化 CreateDomain オーバーロードが、部分信頼アセンブリに対してサポートされる基本のサンドボックス化メカニズムになりました。昨年 10 月号で紹介した Silverlight でのセキュリティ透過性モデルの強化も、デスクトップ フレームワークに移植され、Silverlight プラットフォームと同様に、効率的で簡潔に部分信頼ライブラリを開発できるようになりました。

これらの変更は、ほとんどのアプリケーションがこれまでと変わらず機能するような形で実施しましたが、ホスト開発者やライブラリ開発者の方には、より簡潔なモデルで作業し、より確定的で、使いやすく、したがってセキュリティを確保しやすいモデルをご利用いただけます。       

Andrew Dai は、マイクロソフトの CLR セキュリティ チームのプログラム マネージャーを務めています。この記事で紹介した機能の使い方の詳細については、CLR チームのブログ (blogs.msdn.com/clrteam、英語) および Shawn Farkas の .NET セキュリティのブログ (blogs.msdn.com/shawnfa、英語) を参照してください。