解説
インサイド .NET Framework
第12回 コード・アクセス・セキュリティ(その4 前編)
インフォテリア株式会社
吉松 史彰
2002/12/26
|
|
ここで注意しなければならないのは、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メソッドを開発者が自分で呼び出す必要はないし、それは無駄であると書いてある*。しかし、上記のTestInternalメソッドの実装を見てほしい。もし先頭でDemandメソッドを呼び出していなかったら、アクセス許可のチェックは「非常に時間のかかる処理」の後に行われることになる。「非常に時間のかかる処理」が済んだ後でセキュリティ例外が発生して結局目的が達成できなかったら、ユーザーはどう思うだろうか。「それなら『非常に時間のかかる処理』の前にチェックしてくれよ!」というのが普通の反応であろう。こういうときには、Demandメソッドを自分で呼び出す必要があるのだ。
属性による指定
任意のタイミングで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属性によるアクセス許可チェックの実装例 |
以上、今回はDemandメソッドによるアクセス許可チェックの仕組みについて解説してきたが、このチェックが行われるのはメソッドの実行時であり、これだけでは悪意のあるコードを完全に阻止することはできない。そのため、別のタイミングで、あるいはより厳密な条件で、アクセス許可をチェックする仕組みが.NET Frameworkには用意されている。次回後半ではそれらについて解説する。
Insider.NET 記事ランキング
本日
月間