解説インサイド .NET Framework第13回 コード・アクセス・セキュリティ(その4 後編) インフォテリア株式会社 |
アセンブリ・レベルでの宣言セキュリティ
前回冒頭のDBAccessアセンブリの例をもう一度考えてみよう。DBAccessアセンブリにはTestというメソッドが1つだけ定義されたDBAccessというクラスが1つだけ定義されている。Testメソッドの内部ではSQL Serverにアクセスするので、SqlClientPermissionが必要になる。Demandによってアクセス許可のチェックが行われるので、アクセス許可が与えられていないときにはSQL Serverにはアクセスできないようになっている。
ところで、SQL Serverにアクセスする許可が与えられていなかったら、DBAccessアセンブリをロードする意味があるだろうか? この場合は、明らかに「意味はない」といっていいだろう。つまりDBAccessアセンブリは、「最低でもSqlClientPermissionが与えられていなければ、その環境にロードする必要はない」ということになる。
このように、アセンブリに最低限必要なアクセス許可を定義して、アセンブリのロード時にそれをチェックできるように、.NET Frameworkにはアセンブリ・レベルで属性を付けることもできるようになっている。DBAccessアセンブリの場合、次のようにソース・コードの先頭に属性を設定しておけば、SqlClientPermissionが与えられていない環境ではアセンブリそのものをロードできなくなる。アセンブリをロードして、クラスをロードし、それからアクセス許可をチェックするのに比べると、無駄な動作が減るので効率がよい。
[assembly: SqlClientPermissionAttribute(SecurityAction.RequestMinimum, Unrestricted=true)]
アセンブリ・レベルの属性では、次の表2にある3種類のSecurityActionを設定できる。アセンブリがロードされるタイミングでチェックが行われるので、この3種類もInheritanceDemandやLinkDemandと同様に、コードで書くことはできない。
SecurityAction | 内容 |
RequestMinimum | アセンブリに最低限必要なアクセス許可 |
RequestOptional | アセンブリに指定されている以外のアクセス許可を与えない |
RequestRefuse | アセンブリにアクセス許可が与えられていた場合はDenyと同じくそれを無効にする |
表2 アセンブリ・レベルの属性で設定できる3種類のSecurityAction |
例えばあるアセンブリにFullTrustアクセス許可セットが与えられていて、次のようにアセンブリ・レベルの属性が設定されていたとすると、実際に適用されるアクセス許可は「PrintingPermission(すべての権限)」以外のすべてのアクセス許可となる。つまり、指定されていないFileIOPermissionやUIPermissionも与えられる(FullTrustであるため)。
[assembly: SqlClientPermissionAttribute(SecurityAction.RequestMinimum, Unrestricted=true)]
[assembly: PrintingPermissionAttribute(SecurityAction.RequestRefuse, Unrestricted=true)]
RequestRefuseというSecurityActionは、文字どおり指定されたアクセス許可の適用を明示的に拒否することを意味する。ポリシーの定義によると与えてもいいとなっているアクセス許可を、自らの意思で拒否するわけだ。あるアセンブリから他人が開発したアセンブリを呼び出すような場合には、あらかじめ自分自身が持つアクセス許可機能を絞り込んでしまうことで、信用のおけないアセンブリを呼び出したとしても、悪意のコードの実行に加担してしまうことがないようにできるのだ。
一方、FullTrustを持つアセンブリに次のようにアセンブリ・レベルの属性が設定されていたとすると、実際に適用されるアクセス許可は「SqlClientPermission(制限なし)」と「FileIOPermission(制限なし)」だけになる。つまり、指定されていないPrintingPermissionやUIPermissionは与えられない。
[assembly: SqlClientPermissionAttribute(SecurityAction.RequestMinimum, Unrestricted=true)]
[assembly: FileIOPermissionAttribute(SecurityAction.RequestOptional, Unrestricted=true)]
RequestOptionalを指定すると、指定したアクセス許可は与えられるが、そのほかのアクセス許可はすべて与えられなくなる。RequestRefuseがDenyに相当し、RequestOptionalがPermitOnlyに相当すると考えればいいだろう。ただし、RequestOptionalで指定されたアクセス許可が、ポリシーの評価段階で作成されたアクセス許可セットにそもそも含まれていなくても、RequestMinimumとは違って例外にはならない。そのため、「Optional」という名前になっている。
AllowPartiallyTrustedCallersAttribute
ところで、DBAccessアセンブリのソース・コードには、まだ説明していない属性が1つ付けられている。System.Security.AllowPartiallyTrustedCallersAttributeである。この属性は、.NET Framework 1.0のリリース直前に付け加えられたもので、ドキュメントには載っていない*2。
*2 リリース直後にMSDN Onlineで提供されているドキュメントで解説されているので、「アンドキュメンテッド」というわけではない。また、.NET Framework 1.1のドキュメントには含まれている。 ・Microsoft .NET Frameworkにおけるセキュリティの変更点 ・.NET FrameworkアセンブリとAllowPartiallyTrustedCallers属性 |
この属性は、厳密名が付けられているアセンブリに対してのみ作用する。厳密名付きで、しかもこの属性が付いていないアセンブリには、FullTrustのアクセス許可セットを持たないアセンブリからはアクセスできないようになっているのだ。前回冒頭のDBAccessアセンブリのソース・コードにこの属性が付いているのに気付いただろうか。これは、後でPermTestアセンブリがLocalIntranetのアクセス許可を持つ状態で起動し、DBAccessアセンブリにアクセスするためだ。
DBAccessアセンブリには、構成ファイルで場所を指定するために、厳密名が付けられている。このDBAccessアセンブリにAllowPartiallyTrustedCallersAttribute属性が付いていなかった場合、そもそもLocalIntranetアクセス許可のコードからはDBAccessアセンブリをロードすることができない。そのため、あらかじめこの属性を付けておいたのだ。
本連載の最初の方で解説したとおり、業務システムとして開発されるアセンブリはほぼすべてが厳密名を持っているはずだ。厳密名を持っているアセンブリは、GACにインストールしたり、セキュリティ・ポリシーを変更したりして、比較的強い権限で動作するように設定されることが多いと考えられる。インターネットからダウンロードされたような、信用できないアセンブリがそのような強い権限で動作するアセンブリを呼び出すと、セキュリティ上の問題になることがある。そこで、Microsoftは.NET Frameworkの出荷直前にこの仕組みを追加して、FullTrustを持っていないアセンブリが厳密名付きアセンブリをロードできないようにした。そして、どうしてもロードしなければならないアセンブリのために、AllowPartiallyTrustedCallersAttribute属性を提供した。FullTrustでないアセンブリから厳密名付きのアセンブリにアクセスしたい場合は、その厳密名付きのアセンブリにAllowPartiallyTrustedCallersAttribute属性が付いていなければならない。
まとめ
今回は、開発者と管理者の双方が知っていなければならない、アクセス許可について掘り下げて解説した。アクセス許可の知識とポリシーやエビデンスの知識があれば、管理者は自分が管理している環境に最適なポリシーを定義することもできる。開発者は自分のコードが不用意に悪意のあるコードに加担することを防ぐことができる。
.NET Frameworkクラス・ライブラリに含まれているコードでは、外部のリソースへのアクセスをすべてチェックしている。しかし、単なるメソッドの呼び出しに対しても、そのシステム独自のセキュリティ要件があることもあるだろう。その場合は、開発者が自分でDemandやPermitOnlyなどのコードを記述する必要があるかもしれない。このあたりについてのガイドラインが、マイクロソフトのMSDN Onlineに掲載されている(.NET Frameworkのための安全なコーディング・ガイドライン)。ぜひ参考にしてほしい。
INDEX | ||
解説 インサイド .NET Framework | ||
第13回 コード・アクセス・セキュリティ(その4 後編) | ||
1.型のロード時におけるチェック | ||
2.JITコンパイル時のチェック | ||
3.アクセス許可を取り戻す | ||
4.アセンブリ・レベルでの宣言セキュリティ | ||
「解説:インサイド .NET Framework 」 |
- 第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用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|