クラス ライブラリのセキュリティ

クラス ライブラリのデザイナは、安全なクラス ライブラリを作成するために、コード アクセス セキュリティを理解する必要があります。クラス ライブラリを作成するときは、アクセス許可でオブジェクトを保護することと、完全に信頼されたコードを作成することの 2 つのセキュリティ原則を考慮します。これらの原則をどの程度適用するかは、作成するクラスによって異なります。System.IO.FileStream クラスなどのクラスは、アクセス許可で保護する必要があるオブジェクトを表します。これらのクラスの実装では、呼び出し元のアクセス許可を確認し、アクセス許可を与えられている操作を承認された呼び出し元だけが実行できるようにする必要があります。System.Security 名前空間には、作成するクラス ライブラリでこれらの確認を実行できるようにするクラスが含まれています。クラス ライブラリ コードは、多くの場合は完全に信頼されたコードであり、そうではない場合も、少なくとも高度に信頼されたコードです。クラス ライブラリ コードは保護されているリソースおよびアンマネージ コードにアクセスするため、そのコードに欠陥があると、セキュリティ システム全体の整合性に関して深刻な問題が発生します。セキュリティの問題を最小に抑えるには、クラス ライブラリ コードを作成するときに、このトピックで説明するガイドラインに準拠してください。詳細については、「安全なクラス ライブラリの作成」を参照してください。

アクセス許可によるオブジェクトの保護

アクセス許可を定義して、特定のリソースを保護します。保護されたリソースに対して操作を実行するクラス ライブラリでは、この保護を強制的に実施する必要があります。ファイルの削除など、保護されているリソースに対する要求に応えてアクションを実行する前に、まず、クラス ライブラリ コードで、そのリソースを削除するための適切なアクセス許可が呼び出し元に与えられていることを確認する必要があります (通常、スタック ウォークを実行し、すべての呼び出し元を確認します)。呼び出し元にアクセス許可が与えられている場合は、このアクションを完了できます。呼び出し元にアクセス許可が与えられていない場合は、アクションを完了できず、セキュリティ例外が発生します。通常、このような保護は、適切なアクセス許可の宣言チェックまたは強制チェックのいずれかによって、コードに実装します。

クラスでは、直接アクセスからだけではなく、あらゆる手段による外部アクセスからリソースを保護する必要があります。たとえば、キャッシュされたファイル オブジェクトは、実際のデータがメモリのキャッシュから取得され、実際のファイル操作が発生しない場合でも、ファイルの読み取りアクセス許可を確認します。これは、呼び出し元にデータを渡す処理が、呼び出し元が実際の読み取り操作を実行した場合と同じ影響を持つためです。

完全に信頼されたクラス ライブラリ コード

多くのクラス ライブラリは、プラットフォーム固有の機能を COM やシステム API などのマネージ オブジェクトとしてカプセル化した完全に信頼されたコードとして実装されます。完全に信頼されたコードは、システム全体のセキュリティ上の脆弱性を露呈する可能性があります。しかし、クラス ライブラリがセキュリティの観点から正しく作成されている場合は、比較的小さなクラス ライブラリのセットやコア ランタイム セキュリティに対して厳しいセキュリティ上の制限を課すことによって、それよりも大きなマネージ コードの本体でも、これらのコア クラス ライブラリの持つセキュリティ上の利点を享受できます。

一般的なクラス ライブラリ セキュリティのシナリオでは、完全に信頼されたクラスが、アクセス許可で保護されているリソースを公開し、このリソースにネイティブ コード API がアクセスします。この種類のリソースの典型的な例が、ファイルです。File クラスは、ネイティブ API を使用して、削除などのファイル操作を実行します。リソースを保護するには、次の手順に従います。

  1. 呼び出し元が、File.Delete メソッドを呼び出して、ファイル c:\test.txt の削除を要求します。
  2. Delete メソッドは、delete c:\test.txt のアクセス許可を表すアクセス許可オブジェクトを作成します。
  3. File クラスのコードが、スタック上のすべての呼び出し元をチェックし、必要なアクセス許可が各呼び出し元に与えられているかどうかを確認します。与えられていない呼び出し元がある場合は、セキュリティ例外が発生します。
  4. 呼び出し元に FullTrust アクセス許可が与えられていない場合があるため、ネイティブ コードを呼び出せるように、File クラスが FullTrust をアサートします。
  5. File クラスは、ネイティブ API を使用して、ファイルの削除操作を実行します。
  6. File クラスが呼び出し元に制御を戻し、ファイルの削除要求が正常に完了します。

高度に信頼されたコードに関する注意

信頼されたクラス ライブラリのコードには、ほとんどのアプリケーション コードには許可されないアクセス許可が与えられます。また、特別なアクセス許可を必要とはしないが、それらのアクセス許可が与えられているクラスがアセンブリに含まれていることがあります。これは、そのアセンブリにこれらのアクセス許可を必要とする別のクラスが含まれているためです。このような場合は、システムのセキュリティ上の脆弱性が露呈される可能性があります。そのため、高度にまたは完全に信頼されたコードを作成するときは、特に注意が必要です。

信頼されたコードは、システム上の信頼度の低いコードから、セキュリティ ホールを作り出さずに呼び出せるようにデザインします。リソースは、通常、スタック ウォークですべての呼び出し元をチェックすることにより保護されます。呼び出し元に十分なアクセス許可が与えられていない場合、アクセス試行はブロックされます。ただし、信頼されたコードでアクセス許可をアサートする場合は、必要なアクセス許可の確認をそのコードで実行する必要があります。このトピックで既に説明したように、通常は、呼び出し元のアクセス許可チェックの後でアサートを行います。また、高レベルのアクセス許可のアサート回数を最小に抑えることによって、ライブラリが意図せずして公開されてしまう危険性を抑える必要もあります。

完全に信頼されたコードには、暗黙的に、他のすべてのアクセス許可が与えられます。また、タイプ セーフおよびオブジェクトの使用方法に関する規則に違反してもかまいません。プログラミング インターフェイスの側面のうち、リソースの保護とは関係なく、タイプ セーフに違反する可能性がある要素、または通常は呼び出し元から利用できないデータへのアクセスを実現する要素は、セキュリティの問題を引き起こす可能性があります。

パフォーマンス

セキュリティ チェックでは、スタック上にあるすべての呼び出し元についてアクセス許可が確認されます。スタックの深さによっては、これらの操作によって負荷がかかる可能性が高くなります。1 つの操作が、実際にはセキュリティ チェックを必要とする多数の低レベルなアクションで構成されている場合は、呼び出し元のアクセス許可を 1 回だけ確認し、必要なアクセス許可をアクションを実行する前にアサートすることによって、パフォーマンスを大幅に向上させることができます。アサートが発生すると、スタック ウォークがスタックの上位には伝わらなくなり、その時点でチェックが中断され、チェックは成功します。通常、この技術によってパフォーマンスが向上するのは、3 回以上のアクセス許可チェックを 1 回で実行する場合です。

クラス ライブラリにおけるセキュリティ上の考慮事項のまとめ

  • 保護されているリソースを使用するクラス ライブラリでは、呼び出し元のアクセス許可の範囲内でだけそれらのリソースを使用できるようにする必要があります。
  • アクセス許可のアサーションは、必要な場合にだけ実行し、行う場合には、必要なアクセス許可チェックを先に実行します。
  • パフォーマンスを向上させるために、セキュリティ チェックを伴う操作を集約し、セキュリティを損なわずにスタック ウォークを限定的に実行するアサートの使用を検討します。
  • 信頼度の低い悪意のある呼び出し元が、クラスを使用してセキュリティによる保護を回避する可能性があることに注意してください。
  • 特定のアクセス許可が与えられた呼び出し元だけがコードを呼び出すことを前提にはしないでください。
  • 他の場所でセキュリティ保護を回避するために使用される可能性があるため、タイプ セーフでないインターフェイスは定義しないでください。
  • 信頼度の低い呼び出し元が、クラスの持つ高い信頼性を利用できるようにする機能をクラス内で公開しないようにしてください。

参照

クラス ライブラリ開発者向けのデザイン ガイドライン | 安全なクラス ライブラリの作成 | コード アクセス セキュリティ |セキュリティおよびカルチャを認識する文字列の操作