保护代码中敏感数据的最佳方法是什么?

我正在研究保护我的代码免受反编译的方法。

这里有几个好的线程描述了混淆和代码打包作为保护代码的可能方法。 但是,当使用字符串方法/属性名称时,混淆不适用于reflection。 很多人根本不建议使用混淆。

所以我现在决定不再使用上述任何一项。 但是我有部分代码需要一种加密 ,例如,带有IP的数据库连接字符串,登录名和密码作为简单的const string存储在代码中,与电子邮件帐户数据相同。

在ASP.NET中,有一个选项可以将敏感数据移动到.config文件并对其进行加密,但这需要服务器密钥,即链接到单个计算机。 我没有读太多关于它,但我想类似的东西可用于桌面应用程序。 但我需要这个在任何安装了应用程序的计算机上工作。

这里有一个问题:是否有方法可以编码/保护这些数据,使其无法与反编译代码一起读取?

第一个建议是永远不要直接在代码中存储任何敏感内容。 无论你多么巧妙地试图对它进行模糊处理,你总是可以对其进行逆向工程。

我已经阅读过诸如将密码分成几个部分,将它们放在代码中的不同位置并在最终使用它们之前通过一系列函数运行它们之类的东西……虽然这会使事情变得更难,但您仍然可以始终监视应用程序使用调试器,最终您将能够检索秘密信息。

如果我正确地解释你的场景,你所拥有的是在某个客户端部署的代码,并且你的代码连接到数据库(我想这也是在客户的监督下),连接到它需要密码。 该密码对于该客户端是已知的,因此试图将其从客户端隐藏起来是相当无用的。 你真正想要的是限制任何不应该知道它的人访问该密码。

您通常通过将敏感信息放在应具有非常严格权限的文件夹中的单独文件中来实现此目的,只有应用程序和少数选定人员才能访问。 然后,应用程序将在运行时需要时访问信息。

另外加密单独的文件也是一个问题 – 如果你这样做,那么有一个密钥涉及再次必须以某种方式保护 – 无限递归就在它的方式:)保护对文件的访问通常是足够的,但如果你真的需要尽可能安全,那么解决方案就是对文件使用基于密码的加密。 但这里的想法不是将密码存储在系统上的另一个位置,而是存储为带外信息(例如,在物理保险库中)并在启动应用程序时输入密码。 这也存在问题:(重新)启动应用程序需要物理存在人员,您仍然可以从运行应用程序的机器的RAM中检索密码。 但如果没有专门的硬件,它可能是最好的。

基于密码的加密的另一个好的替代方案是依赖于特定于操作系统的“密码保险库”,例如Windows的“ 隔离存储” ,它在完全不加密和保持密码带外之间进行权衡。

这不是加密答案,但“安全”的一种方法是通过Web服务进行所有数据库调用。 然后,您的连接凭据将存储在您的安全服务器上,客户端将通过该服务传递所有呼叫。

没有任何敏感存储在你的可重新分配中……

我过去一直在努力解决这个问题,并提出了三种处理问题的方法,但我不确定它们是否完美:

  1. 对值进行模糊处理或加密,并希望获得最佳效果。 当然,加密只是额外的混淆,因为密钥必须与其余部分一起提供。
  2. 通过使用单向加密来消除对密钥本身的需求。 使用私钥生成公钥。 这可用于许可或密码validation。 您使用私钥生成许可证,但可以使用公钥来validation它们。 或者您使用私钥生成可以validation的密码,但不能使用公钥进行反转。
  3. 创建您自己的系统特定的密钥生成机制,类似于ASP.NET使用的机制。 您可以通过为每个安装或站点生成唯一键来限制在步骤1中反转加密/模糊处理的人员的影响。

有很多方法,但实际情况是,如果你真的想保护你的代码,唯一的解决方案是使用“专业”产品:-)不要试图重新发明轮子。 这些产品通常具有加密字符串的选项。 真正的问题是另一个问题:没有专业产品(甚至是专业产品),专家可以简单地设置断点并查看传递给库方法的参数(例如打开连接的参数)。 现在……如果你真的想加密代码的字符串,那就很容易了。 但它会有用吗? 没有。

现在,只是为了没有人将此标记为“不是答案”,我将发布一些简单的加密/解密代码:

 // Generate key. You do it once and save the key in the code var encryptorForGenerateKey = Aes.Create(); encryptorForGenerateKey.BlockSize = 128; encryptorForGenerateKey.KeySize = 128; encryptorForGenerateKey.GenerateKey(); encryptorForGenerateKey.GenerateIV(); var key = encryptorForGenerateKey.Key; var iv = encryptorForGenerateKey.IV; // Encrypt: this code doesn't need to be in the program. You create a console // program to do it var encryptor = Aes.Create(); var encryptorTransformer = encryptorForGenerateKey.CreateEncryptor(key, iv); string str = "Hello world"; var bytes = Encoding.UTF8.GetBytes(str); var encrypted = encryptorTransformer.TransformFinalBlock(bytes, 0, bytes.Length); var encryptedString = Convert.ToBase64String(encrypted); Console.WriteLine(encryptedString); // Decrypt: this code needs to be in the program var decryptor = Aes.Create(); var decryptorTransformer = decryptor.CreateDecryptor(key, iv); byte[] encrypted2 = Convert.FromBase64String(encryptedString) var result = decryptorTransformer.TransformFinalBlock(encrypted2, 0, encrypted2.Length); var str2 = Encoding.UTF8.GetString(result); 

这段代码显然不安全。 任何人都可以反编译程序,添加Console.WriteLine(str2)并重新编译它。

当然,您可以在编译之前对字符串进行加密,但如果您使用的是简单的db或http url,则代码需要以纯文本forms进行加密。

在这种情况下没有真正的保护:每个人都可以监听(断点)指定的方法,并在被调用时看到正在发生的事情,而不是真正阅读你的代码。 所以不,没有真正的保护措施,在某些时候使用混淆,你会用一个纯文本字符串调用一些.NET方法,每个人都可以读取它。

例如,您可以将COM或C ++ dll用于存储加密字符串。 一个非托管的DLL不能被分解,但是,专家们当然可以理解dll的反汇编。 如前所述,有时您需要普通数据,而在那一刻,没有任何保护可以持续。

您唯一能做的就是改变您的架构。

例如,如果您的数据库处于联机状态且您的应用程序是客户端应用程序,则可以使用Web服务进行连接。 然后,您只能公开用户真正需要使用的Web服务,不存在用户编写SQL查询的风险。 然后,您可以在服务器上添加保护逻辑,而不是在客户端上添加。

如果一切都处于脱机状态,那么你可以做的就不多了,你可以使用简单的字符串加密来改变生活,但它永远不会成为真正的保护。

正如Lucas在评论中指出的那样,如果你只有一个部分,那么任何反编译你的应用程序的人都可以对其进行逆向工程并解密你的数据库密码。

关于存储凭据,我通常的做法是始终将它们存储在应用程序配置文件中。 如果那时我需要保护它,我使用SecureString和一些加密。 这可以适用于任何类型的配置信息,而不仅仅是凭据。 这里有一篇关于保护配置文件的文章非常好: 加密.NET app.config文件中的密码

也许你应该阅读更多有关加密web.config http://learn.iis.net/page.aspx/141/using-encryption-to-protect-passwords/的内容。

否则你无能为力。 在代码中存储敏感数据不是一种选择,因为任何拥有reflection器工具的人都可以打开并查看它。 如果您希望代码或变量对每个人都不可见,您应该在私有服务器上创建一个Web服务,该服务器接受数据,通过它的魔法转换它并将其返回给客户端。 这样,发布和检索数据之间的所有内容都是保密的。