はじめに
.NET Frameworkに移行する前、多くの開発者は、Windowsアプリケーションがレジストリ、ファイルシステム、イベントログ、環境変数、プリンタなど、すべてのローカルリソースに自由にアクセスすることを当然のように考えていました。ロールベースのセキュリティ制限という仕組みがあったため、ユーザー(またはアプリケーションを実行しているユーザーコンテキスト)にリソースの使用権限が与えられてさえいれば、アプリケーション実行時にどんなリソースでも自由に使用できるという状況に慣れてしまっていたのです。
しかし、分散コンポーネント主体のシステムが急増した現在、アプリケーションがインターネット/イントラネットサイトやネットワーク共有からコンポーネントをダウンロードして実行することは珍しくなくなりました。そのようなアプリケーションに潜む問題点は明らかです。意図的かどうかは別として、悪意のあるコードが外部からダウンロードされ、ローカルコンピュータや内部ネットワークに大損害を与える可能性があります。また、機密漏洩のようなセキュリティ上の脅威も存在します。
こうした状況で必要とされるのは、アセンブリに付随する何らかの「証拠」に基づいてコードにリソースへのアクセス許可を付与するような統合セキュリティモデルです。.NET Frameworkのコードアクセスセキュリティという機構は、このセキュリティモデルを実現します。本稿では、コードアクセスセキュリティポリシーの定義と設定について説明します。
コードアクセスセキュリティの概要
共通言語ランタイム(CLR)に実装されているコードアクセスセキュリティは、アセンブリに関して収集された「証拠」に基づいて動作します。証拠とは具体的に次のようなものを指します。
- アセンブリの読み込み元
- ソースディレクトリのURL(アセンブリをWebからダウンロードした場合)
- 厳密名(Strong Name)(もしあれば)
- 発行者(デジタル署名付きの場合)
CLRは、収集した証拠に基づいてアセンブリをコードグループに割り当てます。コードグループは逆ツリー状の階層構造を持ちます。各コードグループは、そのグループに割り当てられるアセンブリを指定するただ1つのメンバシップ条件を持ちます。さらに、そのグループ内のアセンブリに許されているアクションを示す一連のアクセス許可を持ちます。.NET Frameworkをインストールすると、既定のコードグループ、メンバシップ条件、およびアクセス許可が有効になり、これによって、コンピュータやネットワークが悪意のあるコードの被害に遭う可能性が低くなります。コードグループについては、後ほどさらに詳しく説明します。
ポリシーレベル
最大4レベルのセキュリティポリシーレベルが存在します。
ポリシーレベル | 設定ファイル |
Enterprise | %Systemroot%\Microsoft.NET\Framework\version\Config\enterprise.config |
Machine | %Systemroot%\Microsoft.NET\Framework\version\Config\security.config |
User | %UserProfile%\Application Data\Microsoft\CLR Security Config\version\security.config |
AppDomain | N/A |
Enterprise、Machine、Userのポリシーレベルでは、セキュリティポリシー設定情報がXMLベースの設定ファイルから読み込まれます。AppDomainポリシーレベルは既定では有効にならず、プログラムで明示的に指定する必要があります。AppDomainポリシーレベルの実装方法については後述します。Userセキュリティポリシーは特定コンピュータの特定ユーザーにのみ適用されます。Machineセキュリティポリシーは特定コンピュータの全ユーザーに適用されます。Enterpriseセキュリティポリシーは特定のActive Directory環境に所属する一群のコンピュータに適用されます。AppDomainセキュリティポリシーはオペレーティングシステムプロセス内で実行されている特定のアプリケーションにのみ適用されます。
コードグループ
ポリシーレベルごとに固有のコードグループセットが存在します。既定のEnterpriseおよびUserセキュリティポリシーレベルには、それぞれただ1つのコードグループが存在します。EnterpriseおよびUserポリシーレベルでは、すべてのアセンブリがこの「All Code」コードグループに割り当てられ、すべてのコードがすべてのリソースに完全信頼の下で(すなわち、無制限に)アクセスできます。一方、通常のMachineセキュリティポリシーレベルには階層化されたコードグループが存在し、各コードグループによってリソースへの具体的なアクセス許可が付与されます。次の図(図1)は、Machineポリシーレベルにおける典型的なコードグループ階層を示しています。
前述のように、CLRが読み込んだ各アセンブリは、そのアセンブリに関して収集された証拠に基づいてMachineポリシーレベルの1つまたは複数のコードグループに割り当てられます。アセンブリがコードグループに割り当てられるのは、コードグループのメンバシップ条件を満たす場合です。CLRは「All Code」コードグループから開始してツリーをスキャンし、アセンブリをメンバとするすべてのコードグループを探します。コードグループのメンバシップ条件を満たさないアセンブリは、そのグループおよびその下位グループのメンバとされません。.NET Frameworkで使用可能なビルトインのメンバシップ条件を表2に示します。
メンバシップ条件 | 説明 |
All Code | すべてのアセンブリがこの条件を満たす |
Application Directory | 特定のディレクトリ内(または現行アプリケーションの子ディレクトリ内)のすべてのアセンブリ |
Hash | 特定ハッシュに一致するハッシュを持つすべてのアセンブリ |
Publisher | 特定の証明書でデジタル署名されたすべてのアセンブリ |
Site | 特定のサイトからダウンロードされたすべてのアセンブリ |
Strong Name | 特定の厳密名と公開キーを持つすべてのアセンブリ |
URL | 特定のURLからダウンロードされたすべてのアセンブリ |
Zone | 以下のいずれかのゾーンに属するすべてのアセンブリ 1.マイコンピュータ 2.インターネット 3.ローカルイントラネット 4.信頼されているサイト 5.信頼されていないサイト |
各コードグループは1つのアクセス許可セットを持ちます。.NET Frameworkには、出荷時にビルトインされた一連のアクセス許可セットがあります。
コードグループに割り当てられたアセンブリには、そのコードグループに対応するアクセス許可が付与されます。アセンブリが特定ポリシーレベルの複数のコードグループに割り当てられた場合は、各コードグループのアクセス許可の和集合が、当該ポリシーレベルにおけるアクセス許可として付与されます。つまり、各コードグループのアクセス許可が追加的に付与されるわけです。
次のケース(図2)で考えてみましょう。この例では、MachineセキュリティポリシーレベルのAll Code、Internet_Zone、Partner_Siteの各コードグループにアセンブリが割り当てられています。
この例で、上記の3つのコードグループに対応するアクセス許可セットはNothing、Internet、LocalIntranetなので、当該アセンブリのMachineセキュリティポリシーレベルにおけるアクセス許可はAll Code、Internet_Zone、Partner_Siteの3つのコードグループのアクセス許可の和集合となります。ただし、特定のアセンブリで実効性を持つのは、各セキュリティポリシーレベルにおけるアクセス許可の積集合となります。つまり、各セキュリティポリシーレベルで他のレベルのアクセス許可を実効的に「否定」したければ、そのアクセス許可を付与しなければよいわけです。図3は、この様子を示しています。
既定のEnterpriseおよびUserセキュリティポリシーレベルでは、すべてのアセンブリに「FullTrust」(完全信頼)アクセス許可が付与されるため、通常はMachineポリシーレベルでアセンブリのアクセス許可が決まります(AppDomainは既定では有効になりません)。