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

时间:2011-10-21 12:50:03

标签: c# .net security protection data-protection

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

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

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

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

以下是问题:有没有办法对这些数据进行编码/保护,以便无法与反编译代码一起阅读?

7 个答案:

答案 0 :(得分:15)

首先建议永远直接存储代码中敏感的内容。你可以始终进行逆向工程,无论你多么聪明地试图对其进行模糊处理。

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

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

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

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

基于密码的加密的另一个好的替代方案是依赖于特定于操作系统的“密码保险库”,例如Windows“Isolated Storage”,在完全不加密和保持密码输出之间需要进行权衡。 -of-频带。

答案 1 :(得分:11)

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

在您的可重新分发中没有存储任何敏感内容......

答案 2 :(得分:5)

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

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

答案 3 :(得分:4)

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

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

// 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)并重新编译。

答案 4 :(得分:3)

当然,您可以在编译之前对字符串进行加密,但如果您使用的是简单的数据库或http网址,那么您的代码需要以纯文本形式进行加密。

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

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

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

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

如果所有内容都处于脱机状态,那么您可以做的事情就不多了,您可以使用简单的字符串加密使生活更加艰难,但它永远不会成为真正的保护。

答案 5 :(得分:3)

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

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

答案 6 :(得分:1)

也许您应该阅读有关加密web.config http://learn.iis.net/page.aspx/141/using-encryption-to-protect-passwords/

的更多信息

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