玄铁剑

成功的途径:抄,创造,研究,发明...
posts - 128, comments - 42, trackbacks - 0, articles - 174

创建自定义加密权限

Posted on 2008-12-09 21:35 玄铁剑 阅读(348) 评论(0)  编辑 收藏 引用 所属分类: ASP.NET相关

Microsoft Corporation

目标

使用本单元以:

  • 开发、实现并使用自定义 CAS 权限。

  • 使用自定义代码访问权限来控制到由 DPAPI 提供的非托管加密功能的访问。

适用于

本单元适用于下列产品和技术:

  • Microsoft® Windows® 2000 Server 和 Windows 2000 Professional、Windows Server™ 2003、Windows XP Professional 操作系统

  • Internet Information Server (IIS)

  • Microsoft .NET Framework 1.1

如何使用本单元

要从本单元受益最多:

  • 您必须具备使用 Visual C# .NET 和 Visual Studio .NET 进行编程的经验。

  • 请阅读“如何创建 DPAPI 库”。该单元演示了如何创建本单元所用的托管 DPAPI 包装程序集。

本页内容

摘要 摘要
须知 须知
创建 EncryptionPermission 类 创建 EncryptionPermission 类
创建 EncryptionPermissionAttribute 类 创建 EncryptionPermissionAttribute 类
在 GAC 中安装权限程序集 在 GAC 中安装权限程序集
更新 DPAPI 托管包装代码 更新 DPAPI 托管包装代码
从中等信任的 Web 应用程序调用 DPAPI 从中等信任的 Web 应用程序调用 DPAPI

摘要

.NET Framework 的代码访问安全性 (CAS) 功能可扩展。这使您能够实现自己的权限以控制到重要自定义功能的访问。

本单元主要说明如何创建自定义 CAS 权限以控制到托管数据保护 API (DPAPI) 包装代码的编程访问。该代码在以下站点的 MSDN 库文章“如何:创建 DPAPI 库”中进行阐述:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT07.asp

须知

代码访问安全性权限必须源自 System.Security.CodeAccessPermission,它可实现由 IPermission 接口定义的 Demand 方法,同时还可实现其他方法,如 IStackWalk 接口定义的 AssertDeny 以及 PermitOnly

代码访问权限(不是身份权限)还可实现 IUnrestrictedPermission 接口,以指示该权限是不受限制的权限集的一部分。这意味着该权限会被自动授予任何具有完全信任的代码。本单元中使用的自定义 EncryptionPermission 的继承层次结构如图 1 所示。

fh15secmod01

图 1. 自定义 EncryptionPermission 继承层次结构

自定义 EncryptionPermission 类维护以下状态:

  • EncryptionPermissionFlag。确定被授予该权限的代码能够加密数据还是解密数据,或二者均可。

  • StorePermissionFlag。确定被授予该权限的代码能够通过机器存储还是当前用户存储使用 DPAPI,或二者均可。

创建 EncryptionPermission 类

EncryptionPermission 类是自定义权限实现,用于授权到非托管 DPAPI 功能的访问。

创建 CustomPermission 类

  1. 创建新的 Visual C#TM 开发工具“类库”项目 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 类添加序列化支持,然后将其从 CodeAccessSecurityIUnrestrictedPermission 导出。.并且,密封该类,如下所示。

    [Serializable]
        public sealed class EncryptionPermission : CodeAccessPermission,
        IUnrestrictedPermission
        
  7. 添加两个私有成员变量以维持权限状态。

    private EncryptionPermissionFlag _permFlag;
        private StorePermissionFlag _storePermFlag;
        
  8. 用以下构造函数替换默认的构造函数。

    // It is convention for permission types to provide a constructor
        // that accepts the PermissionState enumeration.
        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);
        }
        }
        // This constructor allows you to specify the encryption type (encrypt
        // or decrypt) by using the EncryptionPermissionFlag enumeration and the DPAPI
        // key store to use (user or machine) as defined by the StorePermissionFlag
        // enumeration.
        public EncryptionPermission(EncryptionPermissionFlag cipher,
        StorePermissionFlag store)
        {
        _permFlag = cipher;
        _storePermFlag = store;
        }
        public EncryptionPermission()
        {
        _permFlag &= ~EncryptionPermissionFlag.Encrypt |
        EncryptionPermissionFlag.Decrypt;
        _storePermFlag &= ~(StorePermissionFlag.User | StorePermissionFlag.Machine);
        }
        
  9. 添加以下公共属性以允许使用者应用程序设置权限类状态。

    // Set this property to true to allow encryption.
        public bool Encrypt
        {
        set {
        if(true == value)
        {
        _permFlag |= EncryptionPermissionFlag.Encrypt;
        }
        else
        {
        _permFlag &= ~EncryptionPermissionFlag.Encrypt;
        }
        }
        get {
        return (_permFlag & EncryptionPermissionFlag.Encrypt).Equals(
        EncryptionPermissionFlag.Encrypt);
        }
        }
        // Set this property to true to allow decryption.
        public bool Decrypt
        {
        set {
        if(true == value)
        {
        _permFlag |= EncryptionPermissionFlag.Decrypt;
        }
        else
        {
        _permFlag &= ~EncryptionPermissionFlag.Decrypt;
        }
        }
        get {
        return (_permFlag & EncryptionPermissionFlag.Decrypt).Equals(
        EncryptionPermissionFlag.Decrypt);
        }
        }
        // Set this property to true to use the DPAPI machine key.
        public bool MachineStore
        {
        set {
        if(true == value)
        {
        _storePermFlag |= StorePermissionFlag.Machine;
        }
        else
        {
        _storePermFlag &= ~StorePermissionFlag.Machine;
        }
        }
        get {
        return (_storePermFlag & StorePermissionFlag.Machine).Equals(
        StorePermissionFlag.Machine);
        }
        }
        // Set this property to true to use the DPAPI user key.
        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)
        {
        // An input of null indicates a permission with no state.
        // There can be no common state, so the method returns null.
        if (target == null)
        return null;
        if (!(target.GetType().Equals(this.GetType())))
        throw new ArgumentException(
        "Argument must be of type EncryptionPermission.");
        // Cast target to an 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(
        "Argument must be of type EncryptionPermission.");
        // Cast the target to an 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。该方法会返回一个布尔值,以指示当前权限是否是提供权限的子集。要成为子集,则当前权限中状态的每一项也必须位于目标权限内。

    public override bool IsSubsetOf(IPermission target)
        {
        // An input of null indicates a permission with no state.
        // The permission can only be a subset if it's in a similar empty 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(
        "Argument must be of type EncryptionPermission.");
        // Cast the target to an 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);
        // Every value set (true) in this permission must be in the target.
        // The following code checks to see if the current permission is a subset
        // of the target. If the current permission has something that the target
        // does not have, it cannot be a subset.
        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.ToXmlFromXml。这些方法将权限对象的实例转换为 XML 格式,反之亦然。这些方法用于支持序列化。例如,在将安全属性存储在程序集元数据中时使用这些方法。

    public override SecurityElement ToXml()
        {
        // Create a new element. The tag name must always be IPermission.
        SecurityElement elem = new SecurityElement("IPermission");
        // Determine the fully qualified type name (including the assembly name) of
        // the EncryptionPermission class. (The security system uses this name to
        // locate and load the class.)
        string name = typeof(EncryptionPermission).AssemblyQualifiedName;
        // Add attributes for the class name and protocol version.
        // The version must currently be 1.
        elem.AddAttribute("class", name);
        elem.AddAttribute("version", "1" );
        if (IsUnrestricted())
        {
        // Using the Unrestricted attribute is consistent with the
        // built-in .NET Framework permission types and helps keep
        // the encoding compact.
        elem.AddAttribute("Unrestricted", Boolean.TrueString);
        }
        else
        {
        // Encode each state field as an attribute of the Permission element.
        // To compact, encode only nondefault state parameters.
        elem.AddAttribute("Flags", this._permFlag.ToString());
        elem.AddAttribute("Stores", this._storePermFlag.ToString());
        }
        // Return the completed element.
        return elem;
        }
        // Converts a SecurityElement (or tree of elements) to a permission
        // instance.
        public override void FromXml(SecurityElement elem)
        {
        string attrVal = "";
        // Check for an unrestricted instance.
        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;
        }
        //Turn off the permission and store flags.
        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 |      // Can use on methods
        AttributeTargets.Constructor | // Can use on constructors
        AttributeTargets.Class |       // Can use on classes
        AttributeTargets.Struct |      // Can use on structures
        AttributeTargets.Assembly,     // Can use at the assembly level
        AllowMultiple = true,          // Can use multiple attribute
        // instances per program element
        // (class, method and so on)
        Inherited = false)]            // Can not be inherited
        
  5. 向该类添加私有成员变量以镜像由关联的权限类维持的状态。

    // The following state fields mirror those used in the associated
        // permission type.
        private bool _encrypt = false;
        private bool _decrypt = false;
        private bool _machineStore = false;
        private bool _userStore = false;
        
  6. 用以下构造函数替换默认的构造函数。

    // Pass the action code back to the base class.
        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()
        {
        // The runtime automatically provides a property to indicate
        // whether or not an unrestricted instance is required.
        if((Unrestricted) || ((_encrypt && _decrypt) &&
        (_userStore && _machineStore)))
        {
        return new EncryptionPermission(PermissionState.Unrestricted);
        }
        // Copy the state from the attribute to the permission object
        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 the final permission.
        return new EncryptionPermission(cipher, store);
        }
        
  9. 生成解决方案。

在 GAC 中安装权限程序集

您必须对实现自定义安全权限的所有程序集授予完全信任。实际上,这意味着您需要在使用程序集的计算机上安装该程序集,以确保默认的安全策略授予其完全信任。My_Computer_Zone 内的代码由默认的策略授予完全信任。

在 GAC 中安装程序集是确保代码访问安全策略授予其完全信任的一种方法。GAC 是适合于权限程序集的位置,原因在于该程序集由本地计算机上的代码访问安全策略使用,并且它对于本地计算机上安装的所有 .NET Framework 应用程序均可用。

要在本地计算机的 GAC 中安装自定义权限程序集,请运行以下命令。

gacutil.exe /i custompermission.dll

更新 DPAPI 托管包装代码

.NET Framework 类库目前并未公开 DPAPI 功能。要从 .NET Framework 应用程序调用 DPAPI,必须使用 P/Invoke。有关演示如何创建托管 DPAPI 包装程序集的代码的信息,请参阅“How To Create a DPAPI Library”。

不做进一步的修改,您只可从完全信任代码调用参考“如何……”方法文章中的托管 DPAPI 包装。若要能够从部分信任代码(例如,中等信任的 ASP.NET Web 应用程序)调用 DPAPI 包装,您必须将对非托管 DPAPI 函数的调用置于沙箱内方可。为此,需进行以下修改:

  • 宣告 DPAPI 包装代码中的非托管代码权限。这意味着任何调用代码均不要求非托管代码权限。

  • 通过要求自定义 EncryptionPermission 在包装内授权调用代码。根据 Demand/Assert 使用模式,Demand 调用在 Assert 调用前出现。有关安全使用 Assert 的详细信息,请参阅单元“Code Access Security in Practice”中的“Assert and 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 块顶端添加以下代码。

    // Set the storeFlag depending on how the caller uses
        // the managed DPAPI wrapper.
        StorePermissionFlag storeFlag;
        if(Store.USE_MACHINE_STORE == store)
        {
        storeFlag = StorePermissionFlag.Machine;
        }
        else
        {
        storeFlag = StorePermissionFlag.User;
        }
        // Demand custom EncryptionPermission.
        (new EncryptionPermission(EncryptionPermissionFlag.Encrypt, storeFlag)).
        Demand();
        // Assert the unmanaged code permission.
        (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert();
        // Now use P/Invoke to call the unmanaged DPAPI functions.
        
  5. 将以下 finally 块添加到该 Encrypt 方法中的外部 try 块。

    finally
        {
        CodeAccessPermission.RevertAssert();
        }
        
  6. 找到 dataprotection.cs 中的 Decrypt 方法,并将以下代码添加到外部 try 块的顶端。

    StorePermissionFlag storeFlag;
        if(Store.USE_MACHINE_STORE == store)
        {
        storeFlag = StorePermissionFlag.Machine;
        }
        else
        {
        storeFlag = StorePermissionFlag.User;
        }
        // Demand custom EncryptionPermission.
        (new EncryptionPermission(EncryptionPermissionFlag.Decrypt, storeFlag)).
        Demand();
        // Assert the unmanaged code permission.
        (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert();
        
  7. 将以下 finally 块添加到该 Decrypt 方法中的外部 try 块。

    finally
        {
        CodeAccessPermission.RevertAssert();
        }
        

从中等信任的 Web 应用程序调用 DPAPI

要从中等信任的 Web 应用程序或任何部分信任的代码使用 DPAPI 托管包装,您必须配置代码访问安全策略以授予代码自定义 EncryptionPermission

本步骤中,将创建测试 Web 应用程序,然后修改中等信任的 Web 应用程序的 ASP.NET 代码访问安全策略以授予其 EncryptionPermission

创建测试 Web 应用程序

  1. 将新的 C# ASP.NET Web 应用程序项目添加当前解决方案。

  2. 向 Dataprotection.dll 程序集添加引用。

  3. 将以下字段添加到 Webform1.aspx。

    • 一个用于要加密数据的输入字段。使用 ID txtDataToEncrypt

    • 一个用于已加密数据的字段。使用 ID txtEncryptedData

    • 一个用于已解密数据的字段。使用 ID txtDecryptedData

    • 一个 Encrypt 按钮。使用 ID btnEncrypt

    • 一个 Decrypt 按钮。使用 IDbtnDecrypt

    • 一个用于错误消息的标签。使用 ID lblError

  4. 将以下 using 语句添加到现有 using 语句之下的 WebForm1.aspx.cs 顶端。

    using DataProtection;
        
  5. 添加以下代码以用于 Encrypt 按钮单击事件处理程序。

    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);
        // Not passing optional entropy in this example
        // Could pass random value (stored by the application) for added security
        // when using DPAPI with the machine store.
        txtEncryptedData.Text =
        Convert.ToBase64String(dp.Encrypt(dataToEncrypt,null));
        }
        catch(Exception ex)
        {
        lblError.ForeColor = Color.Red;
        lblError.Text = "Exception.<br>" + ex.Message;
        return;
        }
        lblError.Text = "";
        }
        
  6. 添加以下代码以用于 Decrypt 按钮单击事件处理程序。

    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);
        // Optional entropy parameter is null.
        // If entropy was used within the Encrypt method, the same entropy
        // parameter must be supplied here.
        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. 通过将以下元素添加到 <system.web> 部分内应用程序的 Web.config 文件来配置 Web 应用程序以用于中等信任。

    <trust level="Medium" />
        
  8. 生成解决方案。

修改中等信任策略

  1. 使用 Visual Studio® .NET 或记事本打开中等信任策略文件。该策略文件位于以下位置。

    %windir%\Microsoft.NET\Framework\{version}\CONFIG\web_mediumtrust.config
  2. 通过将以下 <SecurityClass> 元素添加到 <SecurityClasses> 元素来声明 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>
        
    该权限授予中等信任的 Web 应用程序不受限制的 EncryptionPermission,原因在于它允许代码加密和解密数据,以及使用 DPAPI 机器和用户存储。以上元素演示了支持的语法。它等同于以下内容:
        
    <IPermission class="EncryptionPermission"
        version="1" Unrestricted="true" >
        </IPermission>
        

    通过仅使用相关的属性,您可以授予代码限制的权限。例如,要限制代码仅使用机器存储中的机器密钥解密数据,请使用以下元素。

    <IPermission class="EncryptionPermission"
        version="1" Flags="Decrypt"
        Stores="Machine">
        </IPermission>
        
  4. 保存策略文件。

    现在您可以运行测试 Web 应用程序,并验证通过使用部分信任的 Web 应用程序的 DPAPI 可否加密和解密数据。

有关将高权限代码置于沙箱内和使用 ASP.NET 代码访问安全策略的详细信息,请参阅单元“Using Code Access Security with ASP.NET”。

只有注册用户登录后才能发表评论。