24

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

这里有几个很好的线程将混淆和代码打包描述为保护代码的可能方法。然而,它们都不是理想的,当使用字符串方法/属性名称时,混淆不适用于反射。许多人根本不建议使用混淆。

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

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

问题来了:有没有办法对这些数据进行编码/保护,使其不能与反编译的代码一起被读取?

4

7 回答 7

22

第一个建议是永远不要在代码中直接存储任何敏感内容。无论您尝试如何巧妙地混淆它,您都可以对其进行逆向工程。

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

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

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

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

基于密码的加密的另一个不错的替代方法是依赖操作系统特定的“密码库”,例如 Windows 的独立存储,这是在根本不加密和保持密码带外之间的一种权衡。

于 2011-10-21T17:38:49.723 回答
12

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

根本没有任何敏感信息存储在您的可再分发文件中......

于 2011-10-21T13:02:22.090 回答
6

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

  1. 混淆或加密价值并希望最好。当然,加密只是额外的混淆,因为密钥必须与其余部分一起交付。
  2. 通过使用单向加密来消除对密钥本身的需求。使用私钥生成公钥。这可用于许可或密码验证。您使用私钥生成许可证,但公钥可用于验证它们。或者您使用私钥生成可以验证的密码,但不能使用公钥进行反转。
  3. 创建您自己的特定于系统的密钥生成机制,类似于 ASP.NET 使用的机制。您可以通过为每个安装或站点生成唯一密钥来限制某人在步骤 1 中反转加密/混淆的影响。
于 2011-10-21T13:05:46.997 回答
4

You can of course encrypt your string before compiling it, but your code need that in plain text sometime if you are using a simple db or http url.

There is not a real protection in this case: Everyone can listen (breakpoint) to a specified method and when called see what's going on without really reading your code. So no, there is not a real protection against this, also using obfuscation at some point you will call some .NET method with that plain text string, and everyone can read it.

You can for example put a COM or C++ dll for storing encrypted strings. A unmanaged dll is not decompilable, however, expert people can of course understand the disassembly of a dll. And as said before, sometime you will need the plain data, and at that moment, there is no protection that can last.

The only thing you can do is to change your architecture.

For example, if your db is online and your application is a client application, you can connect using web services. Then you can expose only the web services the user really need to use, there is no risk of user writing sql queries. Then you can add the protection logic on the server instead that on the client.

If everything is offline there is not much you can do, you can make life harder using simple string encryption but it will never be a real protection.

于 2011-10-21T13:40:43.617 回答
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)并重新编译它。

于 2011-10-21T12:58:31.977 回答
3

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

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

于 2011-10-21T14:16:47.653 回答
1

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

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

于 2011-10-21T13:00:18.347 回答