印刷用ページ      送信     
クリックして評価とフィードバックをお寄せください
MSDN
MSDN ライブラリ
テクニカルドキュメント
セキュリティ
How To
 [HOWTO] 暗号化のカスタム アクセス許可を作成する方法
[HOWTO] 暗号化のカスタム アクセス許可を作成する方法
公開日: 2004年9月7日 | 最終更新日: 2004年9月7日
トピック

目的 目的
適用対象 適用対象
モジュールの使用方法 モジュールの使用方法
要約 要約
必要な知識 必要な知識
EncryptionPermission クラスを作成する EncryptionPermission クラスを作成する
EncryptionPermissionAttribute クラスを作成する EncryptionPermissionAttribute クラスを作成する
GAC 内にアクセス許可アセンブリをインストールする GAC 内にアクセス許可アセンブリをインストールする
DPAPI マネージ ラッパー コードをアップデートする DPAPI マネージ ラッパー コードをアップデートする
中程度の信頼の Web アプリケーション から DPAPI を呼び出す 中程度の信頼の Web アプリケーション から DPAPI を呼び出す

目的

このモジュールの目的は次のとおりです。

  • カスタム CAS アクセス許可を開発して実装し、使用する。

  • カスタム コード アクセス アクセス許可を使用して、DPAPI により提供されるアンマネージ暗号化機能へのアクセスを制御する。

適用対象

このモジュールは、次の製品およびテクノロジに適用されます。

  • Microsoft® Windows® 2000 Server、Windows 2000 Professional、Windows Server™ 2003、および Windows XP Professional

  • Internet Information Server (IIS)

  • .NET Framework 1.1

モジュールの使用方法

モジュールの効果的な使用方法

  • Visual C# .NET および Visual Studio .NET を使用したプログラミング経験が必要です。

  • モジュール「DPAPI ライブラリを作成する方法」を参照してください。この参照先モジュールには、このモジュールで使用するマネージ DPAPI ラッパー アセンブリの作成方法の説明があります。

要約

.NET Framework のコード アクセス セキュリティ (CAS) 機能は拡張可能です。これにより、重要なカスタム機能へのアクセスを制御する独自のアクセス許可を実装することが可能となります。

このモジュールでは、マネージ データ保護 API (DPAPI) ラッパー コードへのプログラミングによるアクセスを制御するために、カスタム CAS アクセス許可を作成する方法について説明します。このコードは、http://www.microsoft.com/japan/msdn/net/security/SecNetHT07.aspx にある MSDN ライブラリの記事「セキュリティ保護された ASP.NET アプリケーションの構築: 認証、認定、および通信のセキュリティ保護」に掲載されています。

必要な知識

コード アクセス セキュリティ アクセス許可は、System.Security.CodeAccessPermission から派生していなければなりません。System.Security.CodeAccessPermission は、IPermission インターフェイスによって定義された Demand メソッドの実装を提供し、さらに IStackWalk インターフェイスによって定義された Assert、Deny、PermitOnly などのその他のメソッドの実装も併せて提供します。

コード アクセス アクセス許可 (ID アクセス許可ではない) は、IUnrestrictedPermission インターフェイスも実装します。これは、このアクセス許可が制限されていないアクセス許可セットの一部であることを示しています。つまり、このアクセス許可は、完全信頼を持つコードには自動的に付与されます。このモジュールで実装するカスタム EncryptionPermission の継承の階層構造を図 1 に示します。

カスタム EncryptionPermission の継承の階層構造

図 1
カスタム EncryptionPermission の継承の階層構造

カスタム EncryptionPermission クラスは、以下の状態を保持します。

  • EncryptionPermissionFlag: このアクセス許可を与えられたコードに、データの暗号化を許可するかどうか、および暗号化されたデータの暗号化解除を許可するかどうかを決定します。

  • StorePermissionFlag: このアクセス許可を与えられたコードに、コンピュータ ストアでの DPAPI の使用を許可するかどうか、および現在のユーザー ストアでの DPAPI の使用を許可するかどうかを決定します。

EncryptionPermission クラスを作成する

EncryptionPermission クラスは、アンマネージ DPAPI 機能へのアクセスを承認するために使用されるカスタム アクセス許可の実装です。

  • CustomPermission クラスを作成するには

  1. Visual C#® 開発ツールで、CustomPermission という名前のクラス ライブラリ プロジェクトを新規作成し、class1.cs を EncryptionPermission.cs に名前変更します。

  2. アセンブリを GAC 内にインストールできるようにするため、アセンブリに厳密名を追加します。assemblyinfo.cs 内で、次の属性を使用します。

    [assembly: AssemblyKeyFile(@"..\..\CustomPermissions.snk")]
    
  3. アセンブリのバージョンを固定します。

    [assembly: AssemblyVersion("1.0.0.1")]
    
  4. 以下の using ステートメントを EncryptionPermission.cs の先頭に追加します。

    using System.Security;
    using System.Security.Permissions;
    
  5. CustomPermissions 名前空間に、次に示す列挙を追加します。

    [Flags, Serializable]
    public enum EncryptionPermissionFlag
    {Encrypt = 0x01, Decrypt = 0x02}
    
    [Flags, Serializable]
    public enum StorePermissionFlag
    {User = 0x01, Machine = 0x02}
    
  6. [Serializable] 属性で EncryptionPermission クラスにシリアル化サポートを追加し、それを CodeAccessSecurity および IUnrestrictedPermission から派生させます。さらに、次に示すようにクラスをシールします。

    [Serializable]
    public sealed class EncryptionPermission : CodeAccessPermission, 
                                               IUnrestrictedPermission
    
  7. アクセス許可の状態を保持するために、2 つのプライベート メンバ変数を追加します。

    private EncryptionPermissionFlag _permFlag;
    private StorePermissionFlag _storePermFlag;
    
  8. 既定のコンストラクタを次に示すコンストラクタに置き換えます。

    // アクセス許可型では、PermissionState 列挙を受け取る
    // コンストラクタを提供することが慣習になっています。
    public EncryptionPermission(PermissionState state)
    {
      if (state.Equals(PermissionState.Unrestricted))
      {
        _permFlag = EncryptionPermissionFlag.Encrypt | 
                    EncryptionPermissionFlag.Decrypt;
        _storePermFlag = StorePermissionFlag.User | StorePermissionFlag.Machine;
      }
      else
      {
        _permFlag &= ~(EncryptionPermissionFlag.Encrypt | 
                       EncryptionPermissionFlag.Decrypt);
        _storePermFlag &= ~(StorePermissionFlag.User | 
                            StorePermissionFlag.Machine);
      }
    }
    // このコンストラクタでは、EncryptionPermissionFlag 列挙を使用して
    // 暗号化のタイプ(暗号化または暗号化解除)を指定し、
    // さらに使用する DPAPI キーストア (ユーザー ストアまたはコンピュータ ストア) を
    // StorePermissionFlag 列挙で定義されているとおりに指定することができます。
    public EncryptionPermission(EncryptionPermissionFlag cipher, 
                                StorePermissionFlag store)
    {
      _permFlag = cipher;
      _storePermFlag = store;
    }
    public EncryptionPermission()
    {
      _permFlag &= ~EncryptionPermissionFlag.Encrypt | 
                    EncryptionPermissionFlag.Decrypt;
      _storePermFlag &= ~(StorePermissionFlag.User | StorePermissionFlag.Machine);
    }
    
  9. コンシューマ アプリケーションがアクセス許可クラスの状態を設定できるようにするために、以下のパブリック プロパティを追加します。

    							
    // 暗号化を許可するには、このプロパティの値を true に設定します。
    public bool Encrypt
    {
      set {
        if(true == value)
        {
          _permFlag |= EncryptionPermissionFlag.Encrypt;
        }
        else
        {
          _permFlag &= ~EncryptionPermissionFlag.Encrypt;
        }
      }            
      get {
        return (_permFlag & EncryptionPermissionFlag.Encrypt).Equals(
                            EncryptionPermissionFlag.Encrypt);
      }
    }
    
    // 暗号化解除を許可するには、このプロパティの値を true に設定します。
    public bool Decrypt
    {
      set {
        if(true == value)
        {
          _permFlag |= EncryptionPermissionFlag.Decrypt;
        }
        else
        {
          _permFlag &= ~EncryptionPermissionFlag.Decrypt;
        }
      }
      get {
        return (_permFlag & EncryptionPermissionFlag.Decrypt).Equals(
                            EncryptionPermissionFlag.Decrypt);
      }
    }
    // DPAPI コンピュータ キーを使用するには、このプロパティの値を true に設定します。
    public bool MachineStore
    {
      set {
        if(true == value)
        {
          _storePermFlag |= StorePermissionFlag.Machine;
        }
        else
        {
          _storePermFlag &= ~StorePermissionFlag.Machine;
        }
      }            
      get {
        return (_storePermFlag & StorePermissionFlag.Machine).Equals(
                                 StorePermissionFlag.Machine);
      }
    }
    // DPAPI ユーザー キーを使用するには、このプロパティの値を true に設定します。
    public bool UserStore
    {
      set {
        if(true == value)
        {
          _storePermFlag |= StorePermissionFlag.User;
        }
        else
        {
          _storePermFlag &= ~StorePermissionFlag.User;
        }
      }
      get {
        return (_storePermFlag & StorePermissionFlag.User).Equals(
                                 StorePermissionFlag.User);
      }
    }
    
  10. IPermission.Copy を実装します。このメソッドは、現在のアクセス許可インスタンスと全く同じコピーを作成し、それを呼び出し元に返します。

    public override IPermission Copy()
    {
      return  new EncryptionPermission(_permFlag, _storePermFlag);
    }
    
  11. IPermission.Intersect を実装します。このメソッドは、現在のアクセス許可と渡されたアクセス許可の共通部分を取り出してできたアクセス許可オブジェクトを返します。

    public override IPermission Intersect(IPermission target)
    {
    // null が渡された場合、状態を持たないアクセス許可と見なします。
    // 共通の状態が存在し得ないため、null を返します。
      if (target == null)
        return null;
    
      if (!(target.GetType().Equals(this.GetType())))
        throw new ArgumentException(
    "引数は EncryptionPermission 型を使用する必要があります。"};
    
    // target を EncryptionPermission にキャストします。
      EncryptionPermission targetPerm = (EncryptionPermission)target;
    
      EncryptionPermissionFlag intersectEncryption = this._permFlag & 
                                                     targetPerm._permFlag;
      StorePermissionFlag intersectStore = this._storePermFlag &
                                           targetPerm._storePermFlag;
    
      return new EncryptionPermission(intersectEncryption, intersectStore);
    }
    
  12. IPermission.Union を実装します。このメソッドは、現在のアクセス許可と渡されたアクセス許可を結合してできたアクセス許可オブジェクトを返します。

    public override IPermission Union(IPermission target)
    {
      if (target == null)
        return Copy();
    
      if (!(target.GetType().Equals(this.GetType())))
        throw new ArgumentException(
    "引数は EncryptionPermission 型を使用する必要があります。");
    
    // target を EncryptionPermission にキャストします。
      EncryptionPermission targetPerm = (EncryptionPermission)target;
    
      EncryptionPermissionFlag unionEncryption = this._permFlag | 
                                                 targetPerm._permFlag;
      StorePermissionFlag unionStore = this._storePermFlag | 
                                        targetPerm._storePermFlag;
    
      return new EncryptionPermission(unionEncryption, unionStore);
    }
    
  13. IPermission.IsSubsetOf を実装します。このメソッドは、現在のアクセス許可が渡されたアクセス許可のサブセットであるかどうかを示すブール値を返します。現在のアクセス許可が持つすべての状態が target アクセス許可内にも存在すれば、サブセットであるとします。

    public override bool IsSubsetOf(IPermission target)
    {
      // An input of null indicates a permission with no state.
    // 現在のアクセス許可がサブセットとなれるのは、現在のアクセス許可も同じく状態が空である場合だけです。
      bool canEncrypt, canDecrypt;
      bool canUseMachineStore, canUseUserStore;
    
      bool canTargetEncrypt, canTargetDecrypt;
      bool canTargetUseMachineStore, canTargetUseUserStore;
    
      canEncrypt = (this._permFlag & 
                    EncryptionPermissionFlag.Encrypt).
                    Equals(EncryptionPermissionFlag.Encrypt);
      canDecrypt = (this._permFlag & 
                    EncryptionPermissionFlag.Decrypt).
                    Equals(EncryptionPermissionFlag.Decrypt);
      canUseMachineStore = (this._storePermFlag & 
                            StorePermissionFlag.Machine).
                            Equals(StorePermissionFlag.Machine);
      canUseUserStore = (this._storePermFlag & 
                         StorePermissionFlag.User).
                         Equals(StorePermissionFlag.User);
    
      if (target == null)
      {
        if ((canEncrypt == false && canDecrypt == false) && (canUseMachineStore == 
             false  && canUseUserStore == false))
          return true;
        else
          return false;
      }
    
      if (!(target.GetType().Equals(this.GetType())))
        throw new ArgumentException(
    "引数は EncryptionPermission 型を使用する必要があります。");
    
    // target を EncryptionPermission にキャストします。
      EncryptionPermission targetPerm = (EncryptionPermission)target;
    
      canTargetEncrypt = (targetPerm._permFlag & 
                          EncryptionPermissionFlag.Encrypt).
                          Equals(EncryptionPermissionFlag.Encrypt);
      canTargetDecrypt = (targetPerm._permFlag &  
                          EncryptionPermissionFlag.Decrypt).
                          Equals(EncryptionPermissionFlag.Decrypt);
    
      canTargetUseMachineStore = (targetPerm._storePermFlag & 
                                  StorePermissionFlag.Machine).
                                  Equals(StorePermissionFlag.Machine);
      canTargetUseUserStore = (targetPerm._storePermFlag & 
                               StorePermissionFlag.User).
                               Equals(StorePermissionFlag.User);
    
    // このアクセス許可でセットされている (true になっている) すべての値が、target 内でもセットされていなければなりません。
    // 以下のコードは、現在のアクセス許可が target のサブセットであるかどうかを調べます。
    //現在のアクセス許可が、target にはないどれかの状態を持っている場合、
    // 現在のアクセス許可は target アクセス許可のサブセットではありません。
      if(canEncrypt == true && canTargetEncrypt == false)
        return false;
      if(canDecrypt == true && canTargetDecrypt == false)
        return false;
      if(canUseMachineStore == true && canTargetUseMachineStore == false)
        return false;
      if(canUseUserStore == true && canTargetUseUserStore == false)
        return false;
    
      return true;
    }
    
  14. ISecurityEncodable.ToXml および ISecurityEncodable.FromXml を実装します。これらのメソッドは、アクセス許可オブジェクトのインスタンスを XML 形式に変換したり、その逆変換を行います。これらのメソッドは、シリアル化のサポートに使用されます。たとえば、セキュリティ属性をアセンブリ メタデータに保存するときにこれを使用します。

    public override SecurityElement ToXml()
    {
    // 新しい要素を作成します。タグ名は常に IPermission でなければなりません。
      SecurityElement elem = new SecurityElement("IPermission");
    
    // EncryptionPermission クラスの完全限定型名(アセンブリ名を含む)
    // を決定します。(セキュリティ システムは、クラスを探したり読み込んだりする際に
    // この名前を使用します。)
      string name = typeof(EncryptionPermission).AssemblyQualifiedName;
    
    // クラス名とプロトコル バージョンのための属性を追加します。
    // バージョンは、現在のところは 1 でなければなりません。
      elem.AddAttribute("class", name);
      elem.AddAttribute("version", "1" );
    
      if (IsUnrestricted())
      {
    // Unrestricted 属性の使用は .NET Framework の
    // ビルトインのアクセス許可型と一貫性があり、
    // エンコードをコンパクトにするのに役立ちます。
        elem.AddAttribute("Unrestricted", Boolean.TrueString);
      }
      else
      {
    // 各状態フィールドを Permission 要素の属性としてエンコードします。
    // コンパクトにするために、既定値以外の状態パラメータのみをエンコードします。
        elem.AddAttribute("Flags", this._permFlag.ToString());
        elem.AddAttribute("Stores", this._storePermFlag.ToString());
      }
    // 完成した要素を返します。
      return elem;
    }
    
    // SecurityElement (または要素のツリー) をアクセス許可
    // インスタンスに変換します。
    public override void FromXml(SecurityElement elem)
    {
      string attrVal = "";
    // Unrestricted があるかどうかをチェックします。
      attrVal = elem.Attribute("Unrestricted");
      if (attrVal != null)
      {
        if(attrVal.ToLower().Equals("true"))
        { 
          this._permFlag = EncryptionPermissionFlag.Encrypt | 
                           EncryptionPermissionFlag.Decrypt;
          this._storePermFlag = StorePermissionFlag.Machine | 
                                StorePermissionFlag.User;
        }
        return;
      }
    
    // アクセス許可をオフにし、フラグを保存します。
      this._permFlag &= ~(EncryptionPermissionFlag.Encrypt | 
                          EncryptionPermissionFlag.Decrypt);
      this._storePermFlag &= ~(StorePermissionFlag.Machine | 
                               StorePermissionFlag.User);
    
      attrVal = elem.Attribute("Flags");
      if (attrVal != null)
      {
        if(!attrVal.Trim().Equals(""))
        {
          this._permFlag = 
           (EncryptionPermissionFlag)Enum.Parse(typeof(EncryptionPermissionFlag),
                                                       attrVal);
        }
      }
    
      attrVal = elem.Attribute("Stores");
      if (attrVal != null)
      {
        if(!attrVal.Trim().Equals(""))
        {
          this._storePermFlag = 
                      (StorePermissionFlag)Enum.Parse(typeof(StorePermissionFlag), 
                                                             attrVal);
        }
      }
    }
    
  15. IUnrestrictedPermission.IsUnrestricted を実装します。このメソッドは、アクセス許可インスタンスの状態が無制限に設定されている場合に、true を返します。この例の場合、状態が無制限の EncryptionPermission インスタンスは、コード に DPAPI のコンピュータ ストアとユーザー ストアの両方を使用したデータの暗号化と暗号化解除を許可します。

    public bool IsUnrestricted()
    {
      bool canEncrypt, canDecrypt, canUseUserStore, canUseMachineStore;
      canEncrypt = (this._permFlag &
                    EncryptionPermissionFlag.Encrypt).
                    Equals(EncryptionPermissionFlag.Encrypt);
      canDecrypt = (this._permFlag & 
                    EncryptionPermissionFlag.Decrypt).
                    Equals(EncryptionPermissionFlag.Decrypt);
      canUseUserStore = (this._storePermFlag &
                         StorePermissionFlag.User).
                         Equals(StorePermissionFlag.User);
      canUseMachineStore = (this._storePermFlag & 
                            StorePermissionFlag.Machine).
                            Equals(StorePermissionFlag.Machine);
      return ((canEncrypt && canDecrypt) && 
              (canUseUserStore && canUseMachineStore));
    }
    

EncryptionPermissionAttribute クラスを作成する

.NET Framework では、アクセス許可インスタンスをエンコードするために、そのアクセス許可クラスに関連付けられた属性クラスを使用します。宣言型セキュリティの構文をサポートするには、アクセス許可属性が必要です。

  • EncryptionPermissionAttribute クラスを作成するには

  1. 現在のプロジェクトに、新しいクラス ファイル EncryptionPermissionAttribute.cs を追加します。

  2. 新しいファイルの先頭に、以下の using ステートメントを追加します。

    using System.Security;
    using System.Diagnostics;
    using System.Security.Permissions;
    
  3. CodeAccessSecurityAttribute から属性クラスを派生させ、それをシールします。

    public sealed class EncryptionPermissionAttribute : 
                                         CodeAccessSecurityAttribute
    
  4. クラスにシリアル化サポートを追加し、AttributeUsage 属性を使用して、カスタム アクセス許可属性がどこで使用できるのかを示します。

    [Serializable, 
    AttributeUsage(AttributeTargets.Method |      // メソッドで使用可能
    AttributeTargets.Constructor | // コンストラクタで使用可能
    AttributeTargets.Class |       // クラスで使用可能
    AttributeTargets.Struct |      // 構造体で使用可能
    AttributeTargets.Assembly,     // アセンブリ レベルで使用可能
    AllowMultiple = true,          // プログラム要素 (クラス、メソッドなど) ごとに
    // 複数の属性インスタンスを
    // 使用可能
    Inherited = false)]            // 継承不可
    
  5. 対応するアクセス許可クラスで保持されている状態をミラー化するために、プライベート メンバ変数をクラスに追加します。

    // 以下の状態フィールドは、対応するアクセス許可型で使用されている
    // フィールドをミラー化したものです。
    private bool _encrypt = false;
    private bool _decrypt = false;
    private bool _machineStore = false;
    private bool _userStore = false;
    
  6. 既定のコンストラクタを次のコンストラクタに置き換えます。

    // アクション コードを基本クラスに返します。
    public EncryptionPermissionAttribute(SecurityAction action) : base(action)
    {
    }
    
  7. 対応するアクセス許可のクラスで提供されているプロパティをミラー化するために、以下のパブリック プロパティを追加します。

    public bool Encrypt
    {
      get {
        return _encrypt;
      }
      set {
        _encrypt = value;
      }
    }
    public bool Decrypt
    {
      get {
        return _decrypt;
      }
      set {
        _decrypt = value;
      }
    }
    public bool UserStore
    {
      get {
        return _userStore;
      }
      set {
        _userStore = value;
      }
    }
    public bool MachineStore
    {
      get {
        return _machineStore;
      }
      set {
        _machineStore = value;
      }
    }
    
  8. SecurityPermissionAttribute.CreatePermission を実装します。このメソッドは、アクセス許可オブジェクトを作成します。作成したアクセス許可オブジェクトは、シリアル化して、アセンブリのメタデータ内に指定された SecurityAction 列挙で永続化できます。

    public override IPermission CreatePermission()
    {
    // ランタイムは、無制限のインスタンスが必要かどうかを
    // 示すためのプロパティを自動的に提供します。
      if((Unrestricted) || ((_encrypt && _decrypt) && 
                            (_userStore && _machineStore)))
      {
        return new EncryptionPermission(PermissionState.Unrestricted);
      }
    
    // 状態を属性からアクセス許可オブジェクトにコピーします。
      EncryptionPermissionFlag cipher = 0x0;
      StorePermissionFlag store = 0x0;
    
      if(_encrypt)
        cipher |= EncryptionPermissionFlag.Encrypt;
    
      if(_decrypt)
        cipher |= EncryptionPermissionFlag.Decrypt;
    
      if(_userStore)
        store |= StorePermissionFlag.User;
    
      if(_machineStore)
        store |= StorePermissionFlag.Machine;
    
    // できあがったアクセス許可を返します。
      return new EncryptionPermission(cipher, store);
    }
    
  9. ソリューションをビルドします。

GAC 内にアクセス許可アセンブリをインストールする

カスタム セキュリティ アクセス許可を実装するアセンブリには、必ず完全な信頼を与えなければなりません。現実問題としては、これは、アセンブリを使用するコンピュータ上にアセンブリをインストールしなければならないことを意味します。これにより、既定のセキュリティ ポリシーでも確実にアセンブリに完全な信頼を与えることができます。My_Computer_Zone 内のコードは、既定のポリシーで完全な信頼が与えられます。

GAC 内にアセンブリをインストールすることは、コード アクセス セキュリティ ポリシーによってアセンブリに確実に完全な信頼を与える一つの方法です。アセンブリがローカル コンピュータ上のコード アクセス セキュリティ ポリシーで使用され、ローカル コンピュータ上にインストールされているすべての .Net Framework アプリケーションに対して利用可能になるため、GAC は、アクセス許可アセンブリにとって適した場所です。

ローカル コンピュータの GAC 内にカスタム アクセス許可アセンブリをインストールするには、次のコマンドを実行します。

gacutil.exe /i custompermission.dll

DPAPI マネージ ラッパー コードをアップデートする

DPAPI 機能は、現在のところ .NET Framework クラス ライブラリによって公開されてはいません。.NET Framework アプリケーションから DPAPI を呼び出すには、P/Invoke を使用しなければなりません。マネージ DPAPI ラッパー アセンブリを作成するサンプル コードについては、モジュール「DPAPI ライブラリを作成する方法」を参照してください。

何も変更を加えないと、参照先の [HOWTO] 記事にあるマネージ DPAPI ラッパーを完全信頼コードから呼び出すことしかできません。部分的に信頼されているコード (中程度の信頼の ASP.NET Web アプリケーションなど) から DPAPI ラッパーを呼び出せるようにするには、アンマネージ DPAPI 関数の呼び出しをセキュリティで保護しなければなりません。そのために、以下の修正を行います。

  • DPAPI ラッパーのコード内でアンマネージ コード アクセス許可をアサートします。これにより、呼び出し側のコードには一切アンマネージ コード アクセス許可が必要なくなります。

  • カスタム EncryptionPermission を要求することにより、ラッパー内の呼び出し側コードを承認します。Demand/Assert の使用パターンに従って、Assert を呼び出す前に Demand の呼び出しを行います。Assert を安全に使用するための詳細については、モジュール「コード アクセス セキュリティの実践」の「Assert および RevertAssert」を参照してください。

  • DPAPI マネージ ラッパーを修正するには

  1. 「DPAPI ライブラリを作成する方法」の手順に従って、DPAPI マネージ ラッパーをビルドします。

  2. CustomPermission アセンブリへの参照を追加します。

  3. マネージ ラッパー ライブラリから dataprotection.cs を開き、ファイルの先頭にある一連の using ステートメントの後ろに以下の using ステートメントを追加します。

    using System.Security;
    using System.Security.Permissions;
    using CustomPermissions;
    
  4. dataprotection.cs 内で Encrypt メソッドを探し、Encrypt メソッド内にある外側のtry ブロックの先頭に次のコードを追加します。

    // 呼び出し元がマネージ DPAPI ラッパーをどのように使用するかに応じて 
    // storeFlag を設定します。 
    StorePermissionFlag storeFlag;
    if(Store.USE_MACHINE_STORE == store)
    {
      storeFlag = StorePermissionFlag.Machine;
    }
    else
    {
      storeFlag = StorePermissionFlag.User;
    }
    // カスタム EncryptionPermission を要求します。
    (new EncryptionPermission(EncryptionPermissionFlag.Encrypt, storeFlag)).
                                                                   Demand();
    
    // アンマネージ コード アクセス許可をアサートします。
    (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert();
    // これで、P/Invoke を使用してアンマネージ DPAPI 関数を呼び出せます。
    
  5. Encrypt メソッド内にある外側の try ブロックに次の finally ブロックを追加します。

    finally
    {
      CodeAccessPermission.RevertAssert();
    }
    
  6. dataprotection.cs 内で Decrypt メソッドを探し、Decrypt メソッド内にある外側のtry ブロックの先頭に次のコードを追加します。

    StorePermissionFlag storeFlag;
    if(Store.USE_MACHINE_STORE == store)
    {
      storeFlag = StorePermissionFlag.Machine;
    }
    else
    {
      storeFlag = StorePermissionFlag.User;
    }  
    // カスタム EncryptionPermission を要求します。
      (new EncryptionPermission(EncryptionPermissionFlag.Decrypt, storeFlag)).
                                                                  Demand();
    // アンマネージ コード アクセス許可をアサートします。
      (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert();
    
  7. Decrypt メソッド内にある外側の try ブロックに次の finally ブロックを追加します。

    finally
    {
      CodeAccessPermission.RevertAssert();
    }

中程度の信頼の Web アプリケーション から DPAPI を呼び出す

中程度の信頼のWeb アプリケーションや部分的に信頼されているコードから DPAPI マネージ ラッパーを使用するには、コード アクセス セキュリティ ポリシーを構成して、コードにカスタム EncryptionPermission を与える必要があります。

この手順では、テスト Web アプリケーションを作成した後、中程度の信頼の Web アプリケーション用の ASP.NET コード アクセス セキュリティ ポリシーを修正して、中程度の信頼の Web アプリケーションに EncryptionPermission を与えます。

  • テスト用の Web アプリケーションを作成するには

  1. 現在のソリューションに新しい C# ASP.NET Web アプリケーション プロジェクトを追加します。

  2. Dataprotection.dll アセンブリへの参照を追加します。

  3. Webform1.aspx に以下のフィールドを追加します。

    • 暗号化するデータ用の入力フィールド。ID には txtDataToEncrypt を使用します。

    • 暗号化されたデータ用のフィールド。ID には txtEncryptedData を使用します。

    • 暗号化解除されたデータ用のフィールド。ID には txtDecryptedData を使用します。

    • [暗号化] ボタン。ID には、btnEncrypt を使用します。

    • [暗号化解除] ボタン。ID には、btnDecrypt を使用します。

    • エラー メッセージ用のラベル。ID には、lblError を使用します。

  4. WebForm1.aspx.cs の既存の using ステートメントの下に以下の using ステートメントを追加します。

    using DataProtection;
    
  5. [暗号化] ボタンのクリック イベント ハンドラに次のコードを追加します。

    private void btnEncrypt_Click(object sender, System.EventArgs e)
    {
      DataProtector dp = new DataProtector(
                                  DataProtector.Store.USE_MACHINE_STORE );
      try
      {
        byte[] dataToEncrypt = Encoding.ASCII.GetBytes(txtDataToEncrypt.Text);
    // この例では、オプションのエントロピーを渡しません。
    // DPAPI をコンピュータ ストアで使用する場合には、ランダムな値
    // (アプリケーションによって保存) を渡すことによりセキュリティを高めることもできます。
        txtEncryptedData.Text =
                 Convert.ToBase64String(dp.Encrypt(dataToEncrypt,null));
      }
      catch(Exception ex)
      {
        lblError.ForeColor = Color.Red;
        lblError.Text = "例外:<br>" + ex.Message;
        return;
      }
      lblError.Text = "";
    }
    
  6. [暗号化解除] ボタンのクリック イベント ハンドラに次のコードを追加します。

    private void btnDecrypt_Click(object sender, System.EventArgs e)
    {
      DataProtector dp = new DataProtector(DataProtector.Store.USE_MACHINE_STORE);
      try
      {
        byte[] dataToDecrypt = Convert.FromBase64String(txtEncryptedData.Text);
    // オプションのエントロピ パラメータは null にします。 
    // Encrypt メソッド内でエントロピを使用する場合は、同じエントロピ パラメータを指定しなければなりません。
    // ここで、パラメータを指定します。
        txtDecryptedData.Text = 
             Encoding.ASCII.GetString(dp.Decrypt(dataToDecrypt,null));
      }
      catch(Exception ex)
      {
        lblError.ForeColor = Color.Red;
        lblError.Text = "Exception.<br>" + ex.Message;
        return;
      }
      lblError.Text = "";
    }
    
  7. アプリケーションの Web.config ファイルの <system.web> セクションに以下の要素を追加して、Web アプリケーションを中程度の信頼に構成します。

    <trust level="Medium" />
    
  8. ソリューションをビルドします。

  • 中程度の信頼のポリシーを修正するには

  1. Visual Studio® .NET またはメモ帳を使用して、中程度の信頼のポリシー ファイルを開きます。ポリシー ファイルは次の場所にあります。

    %windir%\Microsoft.NET\Framework\{version}\CONFIG\web_mediumtrust.config
    
  2. <SecurityClasses> 要素に、次に示す <SecurityClass> 要素を追加することにより、EncryptionPermission を宣言します。

    <SecurityClass Name="EncryptionPermission" 
                   Description="CustomPermission.EncryptionPermission, 
                                CustomPermission, Version=1.0.0.1, 
                                Culture=neutral, 
                                PublicKeyToken=951cd7d57a536a94"/>
    

    PublicKeyToken 属性の値を、使用するアセンブリ専用の公開キー トークンに設定します。使用するカスタム アクセス許可アセンブリ用の公開キー トークンを抽出するには、次のコマンドを使用します。

    sn -T custompermission.dll
    

    注: 大文字の -T スイッチを使用してください。

  3. 中程度の信頼のポリシー ファイル内で ASP.NET という名前のアクセス許可セットを探し、そこに次のアクセス許可要素を追加します。

    <IPermission class="EncryptionPermission" 
                 version="1" Flags="Encrypt,Decrypt" 
                 Stores="Machine,User">
    </IPermission>
    

    このアクセス許可は、コードにデータの暗号化と暗号化解除を許可し、さらに DPAPI コンピュータ ストアとユーザー ストアの使用を許可するため、結果的に中程度の信頼の Web アプリケーションに無制限の EncryptionPermission を与えることになります。上の要素は、サポートされている構文で記述してあります。これは、次のように記述しても同じ意味になります。

    <IPermission class="EncryptionPermission" 
                 version="1" Unrestricted="true" >
    </IPermission>
    

    関連する属性のみを使用することにより、コードに制限されたアクセス許可を与えることができます。たとえば、コードがコンピュータ ストア内のコンピュータ キーを使用したデータの暗号化解除のみ行えるように制限するには、次のような要素を使用します。

    <IPermission class="EncryptionPermission" 
                 version="1" Flags="Decrypt" 
                 Stores="Machine">
    </IPermission>
    
  4. ポリシー ファイルを保存します。

    これで、テスト用 Web アプリケーションを実行して、部分的な信頼を与えられた Web アプリケーションから DPAPI を使用してデータを暗号化したり暗号化解除したりできることを確認できます。

高い特権を与えられたコードのセキュリティ保護、および ASP.NET コード アクセス セキュリティ ポリシーでの作業方法の詳細については、モジュール 9「ASP.NET でコード アクセス セキュリティを使用する」を参照してください。


© 2008 Microsoft Corporation.All rights reserved. 使用条件  |  商標  |  プライバシー
Page view tracker