zoukankan      html  css  js  c++  java
  • .NET安全系列之五:数据保护API

    从Windows 2000开始,Windows操作系统提供了一套密码学方面的API,称为DPAPI(Data Protection API,数据保护API)。系统中的这套API由crypt32.dll实现,它使用当前用户的登录用户名/密码对来管理密钥。它可以用于标识一个进程、Windows会话或目前使用的机器,从而在用户、进程、会话或机器级别上加密数据从而确保其机密性。同时使用DPAPI可以使我们不用再负责密钥的管理。

    深入一些,这套API还可以管理对用户密码的修改。例如,如果为某个特定用户将数据加密保存后,即使该用户的密钥发生了变化,仍然可以使用那些数据。这项功能依靠保存过期密钥这一机制实现的。

    使用System.Security.Cryptography.ProtectedData类

    下面的例子演示了使用System.Security.Cryptography.ProtectedData类在用户级别保护数据。

    using System.Security.Cryptography; 
    class Program{ 
        static void Main() { 
            string sMsg = "The message to encrypt!"; 
            string sEnc, sDec; 
            System.Text.Encoding utf = new System.Text.UTF8Encoding(); 
            byte[] entropy = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; 
            { 
                byte[] bMsg = utf.GetBytes(sMsg); 
                byte[] bEnc = ProtectedData.Protect(bMsg , entropy , DataProtectionScope.CurrentUser); 
                sEnc = System.Convert.ToBase64String(bEnc); 
            } 
            { 
                byte[] bEnc = System.Convert.FromBase64String(sEnc); 
                byte[] bDec = ProtectedData.Unprotect(bEnc, entropy, DataProtectionScope.CurrentUser); 
                sDec = utf.GetString(bDec); 
            } 
            System.Console.WriteLine("Message : " + sMsg); 
            System.Console.WriteLine("Encrypted: " + sEnc); 
            System.Console.WriteLine("Decrypted: " + sDec); 
        } 
    } 

    ​可以通过设置DataProtectionScope.LocalMachine值来实现在机器级别保护该数据。本例中为加密添加,这意味着,即使进程执行的上下文环境符合要求(即处在正确的用户或机器下),如果不知道加密使用的熵也是无法解密数据。即可以把熵值看成某种形式的辅助密钥。

    使用System.Security.Cryptography.ProtectedMemory类

    使用System.Security.Cryptography.ProtectedMemory类可以获得比ProtectedData类更加精确的保护数据的程度。枚举量MemoryProtectionScope提供了以下选项:

    SameProcess: 表示只有处在同一进程中的代码才能将进过加密的数据解密。

    SameLogon: 表示只有处在同一用户上下文的代码才能将经过加密的数据解密。

    CrossProcess: 表示只要在加密完成后操作系统没有重启,那么在任何进程中执行的任何代码都能将经过加密的数据解密。

    下面的示例演示了此类的使用。注意:被加密的数据的字节数必须是16的倍数。

    using System.Security.Cryptography; 
    class Program { 
        static void Main() { 
            string sMsg = "01234567890123456789012345678901"; 
            System.Text.Encoding utf = new System.Text.UTF8Encoding(); 
            System.Console.WriteLine("Message : " + sMsg); 
            byte[] bMsg = utf.GetBytes(sMsg); 
            ProtectedMemory.Protect( bMsg, MemoryProtectionScope.SameProcess ); 
            System.Console.WriteLine("Encrypted: " + utf.GetString(bMsg)); 
            ProtectedMemory.Unprotect( bMsg, MemoryProtectionScope.SameProcess ); 
            System.Console.WriteLine("Decrypted: " + utf.GetString(bMsg)); 
        } 
    }

    使用System.Security.SecureString类

    字符串在内存中的存储是不加密的,而且由于垃圾回收机制,字符串这种引用类型在销毁之前有一段不受控制的时间。如果某些恶意的人能够访问到Windows进程的页面,将这些字符串暴露在外面是很危险的。

    为了解决如上问题,.NET Framework提供了SecureString类,其采用DPAPI服务并且允许字符串以加密的形式保存在内存中。

    可以通过一个字符数组(使用过后将其设为零)初始化一个SecureString类的实例,或者通过一个字符一个字符的将其构造出来。Marshal类提供了多个方法以供解密一个保存在SecureString类实例中的加密字符串。

    下面示例展示了SecureString类的使用:

    using System; 
    using System.Security; 
    using System.Runtime.InteropServices; 
    class Program { 
        static void Main() {
            SecureString pwd = new SecureString(); 
            ConsoleKeyInfo nextKey = Console.ReadKey( true ); 
            while(nextKey.Key != ConsoleKey.Enter) { 
                pwd.AppendChar( nextKey.KeyChar ); 
                Console.Write( "*" ); 
                nextKey = Console.ReadKey( true ); 
            } 
            Console.WriteLine();
            pwd.MakeReadOnly(); 
            IntPtr bstr = Marshal.SecureStringToBSTR(pwd); 
            // Get an instance of the Sring class 
            // only for the example needs. 
            try{ Console.WriteLine( Marshal.PtrToStringAuto(bstr) ); } 
            finally{ Marshal.ZeroFreeBSTR(bstr); } 
        } 
    } ​

    使用中往往很难避免将一个SecureString在内存中解密,甚至存放在一个字符串。一定要注意需要在特定的内容区域执行此操作,而写使用完后要尽快销毁,以免出现前文提到的安全问题。

    保护特殊文件中的数据

    在应用程序的配置文件中常常包含需要加密的设置。.NET中这通过System.Configuration.Configuration类来实现。下面示例演示了在一个名为TagPassword的配置参数中保存经过加密的MyPassword字符串。

    using System.Configuration; 
    class Program { 
        static void Main() { 
            SavePwd("MyPassword"); 
            System.Console.WriteLine(LoadPwd()); 
        } 
        static void SavePwd(string pwd) { 
            Configuration cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None ); 
            cfg.AppSettings.Settings.Add("TagPassword", pwd ); 
            cfg.AppSettings.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider" ); 
            cfg.Save(); 
        } 
        static string LoadPwd() { 
            Configuration cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None ); 
            return cfg.AppSettings.Settings["TagPassword"].Value; 
        } 
    }

    如上,在保存操作的时候需要进行处理,以指定我们希望保存一个加密的版本,而在配置文件被读取的时候加密信息会自动被解密。

  • 相关阅读:
    ES6 export
    vue-cli3实现分环境打包步骤(给不同的环境配置相对应的打包命令)
    vue.config.js
    npm install 错误 安装 chromedriver 失败的解决办法
    解决JS(Vue)input[type='file'] change事件无法上传相同文件的问题
    CSS设置浏览器滚动条样式
    ELK 性能(3) — 在 Docker 上运行高性能容错的 Elasticsearch 集群
    ELK 性能(2) — 如何在大业务量下保持 Elasticsearch 集群的稳定
    ELK 性能(1) — Logstash 性能及其替代方案
    ElasticSearch 2 (37)
  • 原文地址:https://www.cnblogs.com/lsxqw2004/p/1380721.html
Copyright © 2011-2022 走看看