解説

インサイド .NET Framework

第11回 コード・アクセス・セキュリティ(その3)

インフォテリア株式会社
吉松 史彰
2002/11/29 改訂版はこちら(2003/08/27)

Page1 Page2 Page3 Page4 Page5

始めに

 前回は、アセンブリがロードされるタイミングで、共通言語ランタイム(CLR)がエビデンスを収集する様子を確認した。ロードされた場所、ロードされたアセンブリのさまざまな情報によって、エビデンスが変化することが確認できた。今回は、そのエビデンスを基にして実際に「『できること』と『できないこと』」を決定するために、システム管理者が用意するポリシーについて解説する。

ポリシー

 第9回の解説の中で触れたとおり、現在の.NET Frameworkでは4種類のポリシーを作成することができる。エンタープライズ、マシン、ユーザー、AppDomainの4種類だ。それぞれ何に対して働くポリシーなのかについては、前々回の解説を参照してほしい。これら4種類のポリシーは、それぞれ別の管理者によって作成されることになるだろう。例えば、エンタープライズ・ポリシーを作成するのは、Active Directoryが運用されているネットワーク内のコンピュータに対して全社的に権限を持つ管理者になる。理想的には、CIOの名の下に社内情報システム部門がこのポリシーを決定することになるだろう。反対に、ユーザー・ポリシーは、マシンを利用する個々のユーザーが作成することになる。

 ポリシーというのは一般名詞で、さまざまな文脈で利用される言葉だが、この連載で触れているポリシーとは、.NET Frameworkに固有の、コード・アクセス・セキュリティに関する設定情報が含まれているものだ。ポリシーは、管理しているシステム(ネットワーク)の状態に応じて、システムの管理者が設定するセキュリティ上のルールである。セキュリティ上のルールといっても多様な側面があるのだが、.NET Frameworkのポリシーが定義するルールには、コード・アクセス・セキュリティに関するものだけが含まれる。つまり、どのコード(アプリケーション)にどんな権限を与える/与えないというルールがポリシーで定義されることになる。具体的には、.NET Frameworkのポリシーには、「コード・グループ」と「アクセス許可セット」という2つのものが含まれている。

コード・グループ

 コード・グループは主に、メンバーシップ条件と、対応するアクセス許可セットを組み合わせるためのものである。ポリシーの中でのコード・グループの役割は、メンバーシップ条件に一致するアセンブリにアクセス許可を割り当てることだ。入力されたエビデンスはコード・グループのメンバーシップ条件とマッチングされ、結果としてアクセス許可が出力される。

メンバーシップ条件

 メンバーシップ条件は、あるアセンブリがどのコード・グループに所属するかを判断するためのものだ。コード・グループは、実行時にはSystem.Security.Policy.CodeGroupクラス(の派生クラス)のオブジェクトとしてアクセスできる。このクラスには、System.Security.Policy.IMembershipConditionインターフェイスの実装を返す、MembershipConditionというプロパティがある。このプロパティにアクセスして返されるものが、コード・グループに設定されているメンバーシップ条件である。System.Security.Policy.IMembershipConditionインターフェイスのドキュメントを参照すると、次の表のようなクラスがこのインターフェイスを実装していることが記述されている。一見して分かるとおり、前回解説したホスト・エビデンスに対応するクラスが定義されている。つまり、コード・グループのメンバーシップ条件で判断される特性とは、エビデンスの値であるということになる。

IMembershipConditionの実装クラス 対応するエビデンス
AllMembershipCondition (すべてのエビデンスがこの条件に当てはまる)
ApplicationDirectoryMembershipCondition ApplicationDirectory
HashMembershipCondition Hash
PublisherMembershipCondition Publisher
SiteMembershipCondition Site
StrongNameMembershipCondition StrongName
UrlMembershipCondition Url
ZoneMembershipCondition Zone
IMembershipConditionインターフェイスを実装しているクラスと、そのクラスに対応するエビデンス(名前空間はすべてSystem.Security.Policy)

 例えば、「MyComputerというZoneエビデンスを持っている」というメンバーシップ条件を作成して、その条件を満たすアセンブリが所属するコード・グループを定義することができる。CodeGroupクラスのMembershipConditionプロパティがIMembershipConditionを返し、コレクションや配列は返さないことから分かるように、1つのコード・グループに対しては1つのメンバーシップ条件しか付けることができない。例えば、「ZoneがMyComputerで、かつHashが0123……である」という条件を1つのコード・グループに定義することはできない。ただし、別の方法で同じ機能を実現できるので、その点については後述する。

 ここで前回同様、MainClass.exeとFileReader.dllを利用して、FileReaderアセンブリがどんなコード・グループに属しているのかを調べてみよう。前回の最初の例では、FileReaderアセンブリは次のようなエビデンスを持っていた。

Zone:MyComputer
Url:file://C:/TEMP/FileReader.DLL
Hash:9E C4 8 62 2A BB 2D 7F D3 98 38 9E FD 89 73 41 4 B8 91 56
前回作成したサンプル・プログラムの実行結果例
FileReaderアセンブリが持つ3つのホスト・エビデンス(Zone、Url、Hash)の値を確認した。

 このエビデンスからどのようなコード・グループが割り出されるのかは、次のコードで確認することができる。

using System;
using System.Collections;
using System.Reflection;
using System.Security;
using System.Security.Policy;

class MainClass {
  static void Main(string[] args) {
    FileReader reader = new FileReader(args[0]);
    Assembly asm = reader.GetType().Assembly;

    IEnumerator itor = SecurityManager.PolicyHierarchy();
    while(itor.MoveNext())
    {
      PolicyLevel pl = itor.Current as PolicyLevel;
      Console.WriteLine("{0}:", pl.Label);
      CodeGroup cg = pl.ResolveMatchingCodeGroups(asm.Evidence);
      Recurse(cg, 1);
    }
//    Console.WriteLine(reader.ReadWhole());
  }

  static void Recurse(CodeGroup cg, int level)
  {
    for (int i = 0; i < level; i++)
      Console.Write("\t");
    Console.WriteLine("{0}", cg.Name);
    foreach(CodeGroup child in cg.Children)
      Recurse(child, level + 1);
  }
}
FileReaderアセンブリのコード・グループを表示するサンプル・プログラム1
ポリシーの階層ごとに、FileReaderアセンブリのエビデンスと一致するメンバーシップ条件を持つコード・グループ名を表示する(プログラムのコンパイルには、第9回のFileReader.csが必要)。

 まずFileReaderアセンブリをロードして、そのAssemblyオブジェクトを取得するのは前回と同じだ。次に、System.Security.SecurityManagerクラスのPolicyHierarchyメソッドを呼び出して、IEnumeratorインターフェイスを取得している。これで列挙できるのは、名前のとおりポリシーの階層である。具体的には、エンタープライズ、マシン、ユーザー、AppDomainが列挙されることになる。次のwhileループで、階層ごとにまずその名前(pl.Label)を表示する。次に、そのポリシー階層でResolveMatchingCodeGroupsメソッドを呼び出し、引数としてアセンブリのエビデンスを渡している。このメソッドは、エビデンスを解釈して、それと一致するメンバーシップ条件を持つコード・グループ(CodeGroup)を返してくる。そこで、返されたCodeGroupを引数にしてRecurseメソッドを呼び出している。Recurseメソッドの内部では、まず必要な分だけタブ文字を出力してインデントを行い、次にコード・グループの名前(cg.Name)を表示している。次に、自分の子コード・グループ(cg.Children)を列挙して、その1つ1つについてRecurseメソッドを再び呼び出している。メソッド名のとおり、Recurseメソッドは再帰的に呼び出されている(コード・グループはツリー構造になっており、コード・グループは子コード・グループを持つことができる)。

 このコードを、.NET Frameworkのインストール直後の状態でC:\Tempから実行すると、次のような結果が得られる。

C:\TEMP>MainClass.exe C:\Boot.ini
Enterprise:
    All_Code
Machine:
    All_Code
        My_Computer_Zone
User:
    All_Code
サンプル・プログラム1の実行結果
.NET Frameworkのインストール直後の状態で、C:\Tempからサンプル・プログラム1を実行した場合。

 FileReaderアセンブリが持つエビデンスを入力すると、エンタープライズとユーザーの2つの階層のポリシーでは、All_Codeという名前のコード・グループだけがヒットしており、マシン階層ではAll_Codeと、その子コード・グループであるMy_Computer_Zoneがヒットしているのが分かる。また、デフォルトではAppDomain階層のポリシーは作成されないことも分かるだろう。AppDomainポリシーは、コードで明示的に作成しなければならない(今回はこのポリシーは解説しない)。

 すでに第9回で解説したとおり、.NET Frameworkをインストールするとデフォルトのポリシーが併せてインストールされる。デフォルトのポリシーには、次のようなコード・グループが定義されている。カッコ内はそのコード・グループに属するために必要なメンバーシップ条件である。

デフォルトのポリシーで定義されているコード・グループ
カッコ内はそのコード・グループに属するために必要なメンバーシップ条件。

 デフォルトのポリシーでは、まずアセンブリのエビデンスのうちZoneが評価されて、ZoneMembershipConditionが作成され、所属するコード・グループが決まる。My_Computer_Zoneコード・グループに決定した場合は、さらにStrongNameエビデンスも評価されて、もう1つのコード・グループに所属することもある。Microsoft以外の開発者が作成したアセンブリの場合、デフォルトのポリシーで評価の対象となるのはZoneだけだといっていいだろう。

 デフォルトのポリシーに照らすと、FileReaderアセンブリが持っていたエビデンスは次のように処理される。

  1. エンタープライズ階層では、AllMembershipConditionが一致するので、All_Codeコード・グループに属する。
  2. コンピュータ階層では、AllMembershipConditionが一致するので、All_Codeコード・グループに属する。
  3. コンピュータ階層では、ZoneMembershipConditionが一致するので、My_Computer_Zoneコード・グループにも属する。
  4. ユーザー階層では、AllMembershipConditionが一致するので、All_Codeコード・グループに属する。

 この処理の結果、上記の内容が出力されるわけだ。


 INDEX
  解説 インサイド .NET Framework
  第11回 コード・アクセス・セキュリティ(その3)
  1.コード・グループとメンバーシップ条件
    2.アクセス許可セットとは
    3.アクセス許可の一覧
    4.管理ツールによるセキュリティ・ポリシーの編集
    5.ポリシーの組み合わせ
 
インデックス・ページヘ  「解説:インサイド .NET Framework 」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間