解説

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

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

吉松 史彰
2003/09/03 改訂(改訂前の記事はこちら
Page1 Page2 Page3 Page4 Page5 Page6 Page7

 本稿は、2002/12/26に公開された記事を、.NET Frameworkの新しいバージョンである「.NET Framework 1.1」に対応させ、全面的に加筆・修正を行った改訂版です。

はじめに

Back Issue
1
マネージ・コード/アセンブリ/モジュール
2 アセンブリのアイデンティティ
3 アセンブリのロード
4 アセンブリとバージョン管理
5 アセンブリのロードとセキュリティ
6 コード・アクセス・セキュリティ(その1)
7 コード・アクセス・セキュリティ(その2)
8 コード・アクセス・セキュリティ(その3)

 今回はアクセス許可を取り上げて、それが実際に適用されるタイミングと、そのタイミングを開発者がコントロールする方法を解説する。.NET Frameworkであらかじめ提供されているアクセス許可は、前回(その3)で一覧したので、それを参考にしてほしい。

アクセス許可が適用されるタイミング

 前回一覧したアクセス許可の中に、System.Data.SqlClient.SqlClientPermissionというアクセス許可があった。名前から想像できるとおり、このアクセス許可はSystem.Data.SqlClient名前空間のクラスを使って、SQL Serverにアクセスできるかどうかを制御するためのものだ。それでは、このアクセス許可はいつ適用され、アクセス可能かどうかの判断が行われるのだろうか。

 試しに、次のようなコードを実行してみよう。まず、SqlClient名前空間のクラスを使ってSQL Serverにアクセスするアセンブリを作成する(データベースのユーザー名とパスワードに注意)。

using System;
using System.Data.SqlClient;
using System.Reflection;
using System.Security;

[assembly: AssemblyKeyName("CspContainer"),
           AssemblyVersion("1.0"),
           AllowPartiallyTrustedCallersAttribute]

public class DBAccess {
  public static void Test() {

    SqlConnection cn = new SqlConnection(
        "Server=.;UID=user;PWD=secret;Database=Northwind");

    SqlCommand cmd = new SqlCommand(
        "SELECT FirstName FROM Employees", cn);
    cn.Open();
    SqlDataReader reader = cmd.ExecuteReader();
    while(reader.Read()) {}
    reader.Close();
    cn.Close();
  }
}
SQL Serverにアクセスするサンプル・プログラムDBAccess.cs
(コンパイル方法はcsc /t:library DBAccess.cs)

 次に、このクラスを利用するアプリケーションを作成する。

class PermTest {
  static void Main() {
    DBAccess.Test();
  }
}
DBAccess.csのクラスを利用するサンプル・プログラムPermTest.cs
(コンパイル方法はcsc /r:DBAccess.dll PermTest.cs)

 2つのコードをそれぞれコンパイルしてDLLファイルとEXEファイルにしたら、すでに解説した方法でDBAccessアセンブリがイントラネット・ゾーンからロードされるように、構成ファイル「PermTest.exe.config」を書く(publicKeyTokenやhrefの内容は環境によって異なるので注意)。

<?xml version="1.0"?>
<configuration>
  <runtime xmlns:asm="urn:schemas-microsoft-com:asm.v1">
    <asm:assemblyBinding>
      <asm:dependentAssembly>
        <asm:assemblyIdentity name="DBAccess"
            publicKeyToken="68cfdcf81cfc4124" />
        <asm:codeBase version="1.0.0.0"
            href="file://\\SERVER\SHARE\DBAccess.dll" />
      </asm:dependentAssembly>
    </asm:assemblyBinding>
  </runtime>
</configuration>
DBAccess.dllをイントラネット・ゾーンからロードするための構成ファイルPermTest.exe.config

 出来上がったらPermTest.exeを実行してみよう。次のようなエラーになるはずだ。

C:\TEMP>PermTest.exe

ハンドルされていない例外 : System.Security.SecurityException: 種類 System.Data.SqlClient.SqlClientPermission, System.Data, Version=1.0.3705.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 のアクセス許可の要求に失敗しました。
   at System.Security.CodeAccessSecurityEngine.CheckHelper(PermissionSet grantedSet, PermissionSet deniedSet, CodeAccessPermission dema
nd, PermissionToken permToken)
   at System.Security.CodeAccessSecurityEngine.Check(PermissionToken permToken, CodeAccessPermission demand, StackCrawlMark& stackMark,
Int32 checkFrames, Int32 unrestrictedOverride)
   at System.Security.CodeAccessSecurityEngine.Check(CodeAccessPermission cap, StackCrawlMark& stackMark)
   at System.Security.CodeAccessPermission.Demand()
   at System.Data.SqlClient.SqlConnectionString.Demand(SqlConnectionString constr)
   at System.Data.SqlClient.SqlConnection.Open()
   at DBAccess.Test()
   at PermTest.Main()

失敗したアクセス権限の状態は次のようになっています :
<IPermission class="System.Data.SqlClient.SqlClientPermission, System.Data, Version=1.0.3705.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" AllowBlankPassword="True">
   <add ConnectionString="Server=.;UID=user;Database=Northwind" KeyRestrictions="" KeyRestrictionBehavior="AllowOnly" />
</IPermission>
PermTest.exeの実行時に発生するエラー

CodeAccessPermission.Demand

 上記の例では、SqlConnectionクラスのOpenメソッドの実行時に例外が発生している。例外はSecurityExceptionで、具体的にはSqlClientPermissionアクセス許可が与えられなかったということだ。前回見たとおり、LocalIntranet_Zoneコード・グループに割り当てられているLocalIntranetアクセス許可セットには、SqlClientPermissionが含まれていない。そのため、このアクセス許可セットが適用されたDBAccessアセンブリは、コードの実行ができなかったというわけだ。このように、.NET Frameworkクラス・ライブラリの各クラスには、それが利用するリソースへのアクセス許可をチェックするコードがすでに埋め込まれている。例えば、System.IO.FileStreamクラスのコンストラクタでは、System.Security.Permissions.FileIOPermissionアクセス許可のチェックが行われているし、System.Net.DnsクラスのResolveメソッドの内部では、System.Net.DnsPermissionアクセス許可のチェックが行われている。それでは、埋め込まれているコードとはどんなものだろうか。

 .NET Frameworkでは、すべてのアクセス許可はオブジェクトとして実体化できる。例えば、「SQL Serverデータベースにアクセスできる」というアクセス許可自体をオブジェクトとして扱っているのだ。具体的には、次のようにSqlClientPermissionクラスをインスタンス化すれば、アクセス許可を表すオブジェクトが作成される。

SqlClientPermission perm = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);

 ここで注意しなければならないのは、アクセス許可のオブジェクトを作っても、アクセスが許可されるわけではないということだ。アクセス許可のオブジェクトはあくまでもアクセス許可の状態を表しているだけで、それが適用されるかどうかは作成しただけでは分からない。オブジェクトが示すアクセス許可を要求し、実際に許可を得るためには、次のようにDemandメソッドを呼び出す必要がある。

perm.Demand();

 Demandメソッドは、System.Security.CodeAccessPermissionクラスのメソッドだ。Demandメソッドを呼び出すと、共通言語ランタイム(CLR)があらかじめポリシーから取得したアクセス許可セットを参照し、要求されたアクセス許可が含まれているかどうかをチェックする。含まれていれば何も起こらずに先に進み、含まれていなければSecurityExceptionが発生する。実は、.NET Frameworkクラス・ライブラリのそれぞれのクラスで内部的に行われているのも、すべてDemandメソッドの呼び出しである。


 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 記事ランキング

本日 月間