如何保护代码中的敏感数据?
我正在研究保护我的代码免遭反编译的方法。
这里有几个很好的线程描述了混淆和代码打包作为保护代码的可能方法。然而,它们都不是理想的,当使用字符串方法/属性名称时,混淆不适用于反射。许多人根本不建议使用混淆。
所以我目前决定不接受上述任何一项。 但是,我有部分代码需要某种加密,例如,带有 IP、登录名和密码的数据库连接字符串存储在代码中,如下所示简单的const string
,与电子邮件帐户数据相同。
在 ASP.NET 中,可以选择将敏感数据移动到 .config
文件并对其进行加密,但这需要服务器密钥,即链接到单台计算机。我没有读太多相关内容,但我认为类似的东西也可用于桌面应用程序。但我需要它能够在安装了该应用程序的任何计算机上运行。
是否有方法对此类数据进行编码/保护,使其无法与反编译代码一起读取?
I was examining the ways of protecting my code from decompiling.
There are several good threads here describing obfuscation and code packing as the possible ways of protecting the code. However none of them is ideal, obfuscation doesn't work with reflection when the string method/property names are used. Many people do not recommend to use obfuscation at all.
So I currently decided not to go with any of the above. However, I have parts of the code where I need a sort of encryption, for example, a database connection string with an IP, login and password is stored inside the code as simple const string
, same as email account data.
In ASP.NET there is an option to move the sensitive data to a .config
file and encrypt it, but that requires the server key, i.e. linked to a single computer. I didn't read much about it, but I suppose something similar is available for desktop applications. But I need this to work on any computer where the application is installed.
Are there ways to encode/protect such data so that it cannot be read along with decompiled code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
第一个建议是永远不要直接在代码中存储任何敏感内容。无论您多么巧妙地试图混淆它,您总是可以对其进行逆向工程。
我读过一些内容,例如将密码分成几部分,将它们放在代码中的不同位置,并在最终使用它们之前通过一系列函数运行它们......尽管这使事情变得更困难,但您仍然可以始终监视应用程序使用调试器,最终您将能够检索秘密信息。
如果我正确地解释了您的场景,那么您所拥有的代码将部署在某些客户端的场所,并且您的代码连接到数据库(我认为数据库也在客户端的监督之下),连接到它需要密码。该密码是该客户端已知的,因此尝试向客户端隐藏它是毫无用处的。您要做的是限制任何不应该知道该密码的人访问该密码。
通常,您可以通过将敏感信息放入文件夹中的单独文件中来实现此目的,该文件夹应具有非常严格的权限,只有应用程序和少数选定的人员有权访问。然后,应用程序将在运行时需要时访问该信息。
另外,加密单独的文件结果是一个问题 - 如果你这样做,那么就会涉及一个密钥,再次必须以某种方式保护它 - 无限递归正在发生:) 保护对文件的访问通常就足够了,但如果如果您确实需要尽可能安全,那么解决方案是对文件使用基于密码的加密。但这里的想法不是将密码存储在系统上的另一个位置,而是作为带外信息(例如,在物理保管库中)并在启动应用程序时输入密码。这也有其问题:(重新)启动应用程序需要有人亲自在场,并且您仍然可以从运行应用程序的计算机的 RAM 中检索密码。但这可能是您在没有专用硬件的情况下可以做的最好的事情。
基于密码的加密的另一个好的替代方案是依赖特定于操作系统的“密码库”,例如 Windows 的 隔离存储,这是完全不加密和将密码保留在带外之间的一种权衡。
First advice is to never store anything sensitive in your code directly. You can always reverse engineer that, no matter how cleverly you try to obfuscate it.
I've read about things like breaking a password into several pieces, placing them at different places in the code and running them through a series of functions before finally using them... although this makes things harder, you can still always monitor the application using a debugger and ultimately you will be able to retrieve the secret information.
If I interpret your scenario correctly, what you have is code that is to be deployed at some client's premises and your code is connected to a database (which I suppose is also under the client's supervision), connecting to it requires a password. This password is known to that client, so trying to hide it from the client is rather useless. What you do want is to restrict access to that password from anybody who is not supposed to know it.
You typically achieve this by putting the sensitive information in a separate file in a folder that should have very restrictive permissions, only the application and a handful of selected people should have access. The application would then access the information when needed during runtime.
Additionally encrypting the separate file turns out to be a problem - if you do so then there is a key involved that again would have to be secured somehow - infinite recursion is on it's way :) Securing access to the file is often sufficient, but if you really require to be as secure as possible, then a solution is to use password-based encryption for the file. But the idea here is not to store the password in yet another location on the system, but rather as out-of-band information (e.g. in a physical vault) and entering the password when starting the application. This, too, has its problems: physical presence of a person is required for (re-)starting the application, and you could still retrieve the password from the RAM of the machine where the application is running on. But it is probably the best you can do without specialized hardware.
Another good alternative to password-based encryption would be to rely on OS-specific "password vaults" such as Windows' Isolated Storage, it's sort of a trade-off between not encrypting at all and keeping the password out-of-band.
这不是加密答案,但“保护”这一点的一种方法是通过 Web 服务进行所有数据库调用。然后,您的连接凭据将存储在您的安全服务器上,客户端将通过那里传递所有呼叫。
您的可再分发文件中根本没有存储任何敏感内容......
This isn't an encryption answer, but one way to 'secure' this would be to make all your database calls through a web service. Your connection credentials would then be stored on your secure server and the clients pass all calls through there.
Nothing sensitive stored in your re-distributable at all...
我过去曾解决过这个问题,并提出了三种处理该问题的方法,但我不确定其中任何一种都是完美的:
I have grappled with this problem in the past and come up with three ways of dealing with the problem, but I'm not sure any of them are perfect:
方法有很多,但现实是,如果您真的想保护您的代码,唯一的解决方案就是使用“专业”产品:-) 不要尝试重新发明轮子。这些产品通常具有加密字符串的选项。真正的问题是另一个:如果没有专业产品(甚至有专业产品),专家可以简单地放置一个断点并查看传递给库方法的参数(例如打开连接的参数)。现在...如果您真的想加密代码的字符串,那非常简单。但这有用吗?不。
现在,为了避免有人将其标记为“不是答案”,我将发布一些简单的加密/解密代码:
此代码显然不安全。任何人都可以反编译该程序,添加一个
Console.WriteLine(str2)
并重新编译它。There are tons of methods, but the reality is that if you really want to protect your code, the only solution is to use "professional" products :-) don't try to reinvent the wheel. These products normally have options to encrypt strings. The real problem is another: without a professional product (and even WITH a professional product) an expert can simply put a breakpoint and look at the parameters passed to the library method (for example the one that opens the connections). Now... If you really really want to encrypt the strings of your code, it's quite easy. But would it be useful? No.
Now, just so that no one will mark this as "not an answer", I'll post some simple encryption/decryption code:
This code clearly isn't secure. Anyone can decompile the program, add a
Console.WriteLine(str2)
and recompile it.当然,您可以在编译之前对字符串进行加密,但如果您使用简单的 db 或 http url,则有时您的代码需要以纯文本形式进行加密。
在这种情况下,没有真正的保护:每个人都可以监听(断点)指定的方法,并且在调用时查看发生了什么,而无需真正阅读代码。
所以不,没有真正的保护措施来防止这种情况,而且在某些时候使用混淆,您将使用该纯文本字符串调用一些 .NET 方法,并且每个人都可以阅读它。
例如,您可以放置 COM 或 C++ dll 来存储加密字符串。
非托管dll是不可反编译的,但是,专家当然可以理解dll的反汇编。正如之前所说,有时您会需要纯数据,而在那一刻,没有任何保护可以持续。
你唯一能做的就是改变你的架构。
例如,如果您的数据库在线并且您的应用程序是客户端应用程序,则可以使用 Web 服务进行连接。
那么你可以只暴露用户真正需要使用的Web服务,不存在用户编写sql查询的风险。
然后您可以在服务器上添加保护逻辑,而不是在客户端上添加保护逻辑。
如果一切都处于离线状态,那么您无能为力,您可以使用简单的字符串加密让生活变得更加困难,但它永远不会成为真正的保护。
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.
正如卢卡斯在其评论中指出的那样,如果您只有一件,那么任何反编译您的应用程序的人都可以对其进行逆向工程并解密您的数据库密码。
关于存储凭据,我通常的做法是始终将它们存储在应用程序配置文件中。如果我需要保护它,我会使用 SecureString 和一些加密。这可以适用于任何类型的配置信息,而不仅仅是凭据。这里有一篇关于保护配置文件的非常好的文章: 加密 .NET app.config 文件中的密码
As Lucas pointed out in its comment, if you have only one piece, then anybody decompiling your application can reverse-engineer it and decrypt your database passwords.
About storing credentials, my usual practice is to always store them in the application configuration file. If then I need to secure it, I use a SecureString and some encryption. And this could work for any kind of configuration information, not only credentials. There is a really good article about securing configuration files here: Encrypting Passwords in a .NET app.config File
也许您应该阅读更多有关加密 web.config http://learn.iis.net/page.aspx/141/using-encryption-to-protect-passwords/
否则你无能为力。在代码中存储敏感数据不是一种选择,因为任何拥有反射器工具的人都可以打开它并查看它。如果您希望代码或变量对每个人都不可见,您应该在私有服务器上创建一个 Web 服务来接受数据,通过它的魔力进行转换并将其返回给客户端。这样,发布和检索数据之间的所有内容都是保密的。
Maybe you should read some more on encrypting the web.config http://learn.iis.net/page.aspx/141/using-encryption-to-protect-passwords/
Otherwise there isnt much you can do. Storing sensitive data in code isn't an option since anyone with a reflector tool can open it and see it. If you want code or variables to be invisible to everyone, you should create a webservice on a private server that accepts data, transforms it through it's magic and returns it to the client. In that way everything in between posting and retrieving the data is kept secret.
我不确定是否可以在客户端位置保护您的代码,但解决方案可能是将密码存储在 Azure Key Vault 中并使用 Azure Active Directory 对其进行身份验证。然而,这仍然可以进行逆向工程。您可以在此处阅读更多信息:https://learn.microsoft.com/en -us/azure/key-vault/
I am not sure if it is possible to protect your code at a client location, but a solution might be to store the password in Azure Key Vault and authenticate to it with Azure Active Directory. However, this might still be possible to reverse engineer. You can read more here: https://learn.microsoft.com/en-us/azure/key-vault/