解説

インサイド .NET Framework [改訂版]

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

吉松 史彰
2003/09/03
Page1 Page2 Page3 Page4 Page5 Page6 Page7

 ここで注意しなければならないのは、Demandメソッドはそれを呼び出したメソッド(が所属するアセンブリ)のアクセス許可はチェックしないということだ。SqlClientPermissionの場合、Demandメソッドを呼び出すのはOpenメソッドであるので、Openメソッドが所属するSystem.Dataアセンブリのアクセス許可はチェックされない。本稿のDBAccessアセンブリの場合、TestメソッドでDemandメソッドを呼び出しても、DBAccessアセンブリそのものにアクセス許可が与えられているかどうかは確認できないことになる(図3)。

図3 コールスタックにおけるアクセス許可のチェック(3)
Demandメソッドは、それを呼び出したメソッド(が所属するアセンブリ)のアクセス許可をチェックしない。このため、DBAccessアセンブリに存在するTestメソッドでDemandメソッドを呼び出しても、DBAccessアセンブリそのものにアクセス許可が与えられているかどうかは確認できない。

 それを確認したい場合は、「ドライバ」となるメソッドを間に挟むしかない。具体的には、下のようなコードを書けば、TestInternalメソッドでDemandメソッドを呼び出したときに最初のチェック対象がTestメソッドになるので、結果的にDBAccessアセンブリのアクセス許可をチェックすることが可能になる(図4)。

図4 コールスタックにおけるアクセス許可のチェック(4)
DBAccessアセンブリのアクセス許可をチェックするためには、ドライバとなるメソッド(この場合はTestInternalメソッド)を間に挟む必要がある。
 
public static void Test() {
  TestInternal();
}

static void TestInternal() {
  SqlClientPermission perm = new SqlClientPermission(
    System.Security.Permissions.PermissionState.Unrestricted);
  perm.Demand();
  while(true) {
    // 非常に時間のかかる処理……
    break;
  }
  SqlConnection cn = new SqlConnection("
      Server=.;UID=sa;PWD=;Database=Northwind");

  SqlCommand cmd = new SqlCommand(
      "SELECT FirstName FROM Employees", cn);

  cn.Open();
  SqlDataReader reader = cmd.ExecuteReader();
  while(reader.Read()) {}
  reader.Close();
  cn.Close();
}
TestInternalメソッドを追加したDBAccess.cs

 TestInternalメソッドは、以前のTestメソッドから少し内容が変わっている。.NET Framework SDKのドキュメントによると、SQL Serverやファイルのようなほとんどのリソースにおいて、Demandメソッドの呼び出しがすでに組み込まれているので、Demandメソッドを開発者が自分で呼び出す必要はないし、それは無駄であると書いてある*1。しかし、上記のTestInternalメソッドの実装を見てほしい。もし先頭でDemandメソッドを呼び出していなかったら、アクセス許可のチェックは「非常に時間のかかる処理」の後に行われることになる。「非常に時間のかかる処理」が済んだ後でセキュリティ例外が発生して結局目的が達成できなかったら、ユーザーはどう思うだろうか。「それなら『非常に時間のかかる処理』の前にチェックしてくれよ!」というのが普通の反応であろう。こういうときには、Demandメソッドを自分で呼び出す必要があるのだ。

*1 http://www.microsoft.com/japan/msdn/library/ja/cpguide/html/cpcondemands.asp

属性による指定

 任意のタイミングでDemandメソッドを呼び出せば、そこでアクセス許可のチェックが行われる。しかしほとんどの場合に、アクセス許可のチェックはメソッドの先頭で行われるだろう。そこで.NET Frameworkではカスタム属性の仕組みを使って、必要なアクセス許可をあらかじめ宣言しておくことができる。これを「宣言セキュリティ」と呼んでいる。

 ほとんどのアクセス許可を表すクラスには、それに対応する属性クラスが用意されている。例えばSqlClientPermissionクラスには、SqlClientPermissionAttributeクラスが用意されている。属性クラスの名前は、アクセス許可のクラス名に「Attribute」を付けたものだと考えていいだろう。

 上記のDBAccess.TestInternalメソッドの場合、メソッドの呼び出し時にアクセス許可をチェックすればよいので、次のようにメソッドに対して属性を付けることで、DemandメソッドをTestメソッドの先頭で呼ぶのと同じ効果が得られる。

[SqlClientPermissionAttribute
    (SecurityAction.Demand, Unrestricted=true)]

static void TestInternal() {
  while(true) {
    // 非常に時間のかかる処理……
    break;
  }
  SqlConnection cn = new SqlConnection(
      "Server=.;UID=sa;PWD=;Database=Northwind");

  SqlCommand cmd = new SqlCommand(
      "SELECT FirstName FROM Employees", cn);

  cn.Open();
  SqlDataReader reader = cmd.ExecuteReader();
  while(reader.Read()) {}
  reader.Close();
  cn.Close();
}
SqlClientPermission属性によるアクセス許可チェックの実装例
 

 INDEX
  解説 インサイド .NET Framework [改訂版]
  第9回 コード・アクセス・セキュリティ(その4)
    1.アクセス許可が適用されるタイミング
    2.Demandメソッドの内部動作
  3.属性によるアクセス許可チェックの指定
    4.型のロード時におけるチェック
    5.JITコンパイル時のチェックとDemandの動作の変更
    6.アクセス許可を取り戻す
    7.アセンブリ・レベルでの宣言セキュリティ
  
インデックス・ページヘ  「解説:インサイド .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 記事ランキング

本日 月間