简体   繁体   English

保护胖客户端应用程序中的API密钥

[英]Protecting API Secret Keys in a Thick Client application

Within an application, I've got Secret Keys uses to calculate a hash for an API call. 在一个应用程序中,我使用Secret Keys来计算API调用的哈希值。 In a .NET application it's fairly easy to use a program like Reflector to pull out information from the assembly to include these keys. 在.NET应用程序中,使用像Reflector这样的程序来从程序集中提取信息以包含这些键是相当容易的。

Is obfuscating the assembly a good way of securing these keys? 混淆装配是保护这些钥匙的好方法吗?

Probably not. 可能不是。

Look into cryptography and Windows' built-in information-hiding mechanisms (DPAPI and storing the keys in an ACL-restricted registry key, for example). 查看加密和Windows的内置信息隐藏机制(例如,DPAPI并将密钥存储在ACL限制的注册表项中)。 That's as good as you're going to get for security you need to keep on the same system as your application. 这就像你要获得安全性一样好,你需要与应用程序保持同一系统。

If you are looking for a way to stop someone physically sitting at the machine from getting your information, forget it. 如果您正在寻找一种方法来阻止身体坐在机器上的人获取您的信息,请忘掉它。 If someone is determined, and has unrestricted access to a computer that is not under your control, there is no way to be 100% certain that the data is protected under all circumstances. 如果有人确定,并且无限制地访问不受您控制的计算机,则无法100%确定数据在任何情况下都受到保护。 Someone who is determined will get at it if they want to. 如果他们愿意,有决心的人会得到它。

I wouldn't think so, as obfuscating (as I understand it at least) will simply mess around with the method names to make it hard (but not impossible) to understand the code. 我不这么认为,因为混淆(至少我理解)会简单地弄乱方法名称,以使得理解代码变得困难(但并非不可能)。 This won't change the data of the actual key (which I'm guessing you have stored in a constant somewhere). 这不会改变实际密钥的数据(我猜你已经存储在一个常量的某个地方)。

If you just want to make it somewhat harder to see, you could run a simple cipher on the plaintext (like ROT-13 or something) so that it's at least not stored in the clear in the code itself. 如果你只是想让它更难看,你可以在明文上运行一个简单的密码(比如ROT-13或其他东西),这样它至少不会在代码本身中以明文形式存储。 But that's certainly not going to stop any determined hacker from accessing your key. 但这肯定不会阻止任何坚定的黑客访问你的密钥。 A stronger encryption method won't help because you'd still need to store the key for THAT in the code, and there's nothing protecting that. 更强大的加密方法无济于事,因为您仍然需要在代码中存储密钥,并且没有任何保护。

The only really secure thing I can think of is to keep the key outside of the application somehow, and then restrict access to the key. 我能想到的唯一真正安全的事情是以某种方式将密钥保留在应用程序之外,然后限制对密钥的访问。 For instance, you could keep the key in a separate file and then protected the file with an OS-level user-based restriction; 例如,您可以将密钥保存在单独的文件中,然后使用基于操作系统级别的基于用户的限制来保护该文件; that would probably work. 这可能会奏效。 You could do the same with a database connection (again, relying on the user-based access restriction to keep non-authorized users out of the database). 您可以对数据库连接执行相同的操作(同样,依靠基于用户的访问限制将非授权用户保留在数据库之外)。

I've toyed with the idea of doing this for my apps but I've never implemented it. 我已经玩弄了为我的应用程序执行此操作的想法,但我从未实现它。

Late to the game here... 这场比赛的后期......

The approach of storing the keys in the assembly / assembly config is fundamentally insecure. 将密钥存储在汇编/汇编配置中的方法基本上是不安全的。 There is no possible ironclad way to store it as a determined user will have access. 由于确定的用户可以访问,因此没有可能存储它的铁定方法。 I don't care if you use the best / most expensive obfuscation product on the planet. 如果你使用这个星球上最好/最昂贵的混淆产品,我不在乎。 I don't care if you use PDAPI to secure the data (although this is better). 我不在乎您是否使用PDAPI来保护数据(尽管这样更好)。 I don't care if you use a local OS-protected key store (this is even better still). 我不在乎您是否使用本地受OS保护的密钥存储区(这甚至更好)。 None are ideal as all suffer from the same core issue: the user has access to the keys, and they are there, unchanging for days, weeks, possibly even months and years. 没有一个是理想的,因为所有人都遇到相同的核心问题:用户可以访问密钥,他们在那里,几天,几周甚至几个月甚至几年不变。

A far more secure approach would be is to secure your API calls with tried and true PKI. 一种更安全的方法是使用久经考验的PKI保护您的API调用。 However, this has obvious performance overhead if your API calls are chatty, but for the vast majority of applications this is a non-issue. 但是,如果您的API调用很繁琐,这会产生明显的性能开销,但对于绝大多数应用程序而言,这不是问题。

If performance is a concern, you can use Diffie-Hellman over asymmetric PKI to establish a shared secret symmetric key for use with a cipher such as AES. 如果需要考虑性能,可以使用Diffie-Hellman而不是非对称PKI来建立共享密钥对称密钥,以便与AES等密码一起使用。 "shared" in this case means shared between client and server, not all clients / users. 在这种情况下,“共享”意味着客户端和服务器之间共享,而不是所有客户端/用户。 There is no hard-coded / baked in key. 密钥中没有硬编码/烘焙。 Anywhere. 无处不在。

The keys are transient, regenerated every time the user runs the program, or if you are truly paranoid, they could time-out and require recreation. 键是瞬态的,每次用户运行程序时都会重新生成,或者如果你真的是偏执狂,它们可能会超时并需要重新创建。

The computed shared secret symmetric keys themselves get stored in memory only, in SecureString. 计算出的共享秘密对称密钥本身仅存储在SecureString中的内存中。 They are hard to extract, and even if you do, they are only good for a very short time, and only for communication between that particular client (ie that session). 它们很难提取,即使你这样做,它们只能在很短的时间内完成,并且仅用于特定客户端之间的通信(即该会话)。 In other words, even if somebody does hack their local keys, they are only good for interfering with local communication. 换句话说,即使有人破解了他们的本地密钥,它们也只能干扰本地通信。 They can't use this knowledge to affect other users, unlike a baked-in key shared by all users via code / config. 他们不能使用这些知识来影响其他用户,这与所有用户通过代码/配置共享的烘焙密钥不同。

Furthermore, the entire keys themselves are never, ever passed over the network. 此外,整个密钥本身永远不会通过网络传递。 The client Alice and server Bob independently compute them. 客户端Alice和服务器Bob独立地计算它们。 The information they pass in order to do this could in theory be intercepted by third party Charlie, allowing him to independently calculate the shared secret key. 为了做到这一点,他们传递的信息理论上可以被第三方查理截获,允许他独立计算共享密钥。 That is why you use that (significantly more costLy) asymmetric PKI to protect the key generation between Alice and Bob. 这就是为什么你使用那个(显着更多costLy)非对称PKI来保护Alice和Bob之间密钥生成的原因。

In these systems, the key generation is quite often coupled with authentication and thus session creation. 在这些系统中,密钥生成通常与认证和会话创建相结合。 You "login" and create your "session" over PKI, and after that is complete, both the client and the server independently have a symmetric key which can be used for order-of-magnitude faster encryption for all subsequent communication in that session. 您“登录”并通过PKI创建“会话”,在此之后,客户端和服务器都独立地具有对称密钥,该密钥可用于对该会话中的所有后续通信进行数量级更快的加密。 For high-scale servers, this is important to save compute cycles on decryption over using say TLS for everything. 对于高规模服务器,这对于在解密时节省计算周期比使用所谓的TLS更重要。

But wait: we're not secure yet. 但是等一下:我们还不安全。 We've only prevented reading the messages. 我们只是阻止阅读邮件。

Note that it is still necessary to use a message digest mechanism to prevent man-in-the-middle manipulation. 请注意,仍然需要使用消息摘要机制来防止中间人操作。 While nobody can read the data being transmitted, without a MD there is nothing preventing them from modifying it. 虽然没有人能够读取正在传输的数据,但没有MD就没有什么能阻止他们修改它。 So you hash the message before encryption, then send the hash along with the message. 因此,您在加密前对消息进行散列,然后将散列与消息一起发送。 The server then re-hashes the payload upon decryption and verifies that it matches the hash that was part of the message. 然后,服务器在解密时重新散列有效负载,并验证它是否与作为消息一部分的散列相匹配。 If the message was modified in transit, they won't, and the entire message is discarded / ignored. 如果邮件在传输过程中被修改,则不会,并且将丢弃/忽略整个邮件。

The final mechanism needed to guard against is replay attacks. 需要防范的最终机制是重播攻击。 At this point, you have prevented people from reading your data, as well as modifying your data, but you haven't prevented them from simply sending it again. 此时,您已阻止人们读取您的数据以及修改您的数据,但您还没有阻止他们再次发送数据。 If this is a problem for your application, it's protocol must provide data and both client and server must have enough stateful information to detect a replay. 如果这是您的应用程序的问题,它的协议必须提供数据,并且客户端和服务器必须具有足够的有状态信息来检测重放。 This could be something as simple as a counter that is part of the encrypted payload. 这可能是一个简单的计数器,它是加密有效载荷的一部分。 Note that if you are using a transport such as UDP, you probably already have a mechanism to deal with duplicated packets, and thus can already deal with replay attacks. 请注意,如果您使用的是UDP等传输,则可能已经有了处理重复数据包的机制,因此可以处理重放攻击。

What should be obvious is getting this right is not easy. 应该明白的是,要做到这一点并不容易。 Thus, use PKI unless you ABSOLUTELY cannot. 因此,除非你绝对不能使用PKI。

Note that this approach is used heavily in the games industry where it is highly desirable to spend as little compute on each player as possible to achieve higher scalability, while at the same time providing security from hacking / prying eyes. 注意,这种方法在游戏行业中被大量使用,其中非常希望在每个播放器上花费尽可能少的计算以实现更高的可扩展性,同时提供来自黑客/窥探眼睛的安全性。

So in conclusion, if this is really something that is a concern, instead of trying to find a securely store the API keys, don't. 总而言之,如果这确实是一个问题,而不是试图找到安全存储API密钥,而不是。 Instead, change how your app uses this API (assuming you have control of both sides, naturally). 相反,请更改您的应用使用此API的方式(假设您可以自然控制双方)。 Use a PKI, or use a PKI-shared symmetric hybrid if PKI will be too slow (which is RARELY a problem these days). 如果PKI太慢(这几天很可能是一个问题),请使用PKI,或使用PKI共享的对称混合。 Then you won't have anything stored that is a security concern. 然后,您将不会存储任何安全问题。

DannySmurf is correct that you can't hide keys from the person running an application; DannySmurf是正确的,你无法隐藏运行应用程序的人的密钥; if the application can get to the keys, so can the person. 如果应用程序可以获得密钥,那么该人也可以。

However, What you are trying to accomplish exactly? 但是,您要完成的是什么?

Depending on what it is, there are often ways to accomplish your goal that don't simply rely on keeping a secret "secret", on your user's machine. 根据具体情况,通常有一些方法可以实现您的目标,而不仅仅是依赖于在用户的计算机上保密“秘密”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM