
Protecting API Secret Keys in a Thick Client application在一个应用程序中,我使用了Secret Keys来计算API调用的哈希值。在.NET应用程序中,使用Reflector之类的程序从程序集中提取信息以包含这些键非常容易。 使组件模糊不清是固定这些钥匙的好方法吗? 可能不是。 研究加密技术和Windows内置的信息隐藏机制(例如,DPAPI,并将密钥存储在ACL限制的注册表项中)。这与获得安全性和将应用程序保持在同一系统上一样好。 如果您正在寻找一种方法来阻止有人坐在机器旁来获取您的信息,那就算了。如果确定某人并且可以不受限制地访问不受您控制的计算机,则不可能100%确定在所有情况下数据都受到保护。有决心的人会愿意的。 在这里晚了游戏... 将密钥存储在Assembly / Assembly配置中的方法本质上是不安全的。没有确定的存储方式,因为确定的用户将有权访问它。我不在乎您是否使用地球上最好/最昂贵的混淆产品。我不在乎您是否使用PDAPI保护数据(尽管这样做更好)。我不在乎您是否使用受本地操作系统保护的密钥存储(甚至更好)。没有一个是理想的选择,因为所有人都遭受相同的核心问题:用户可以访问密钥,并且密钥在那里存在,几天,几周甚至几个月甚至几年都没有变化。 一种更加安全的方法是使用经过验证的真实PKI保护您的API调用。但是,如果您的API调用比较闲聊,则这会带来明显的性能开销,但是对于绝大多数应用程序来说,这不是问题。 如果要考虑性能,则可以在非对称PKI上使用Diffie-Hellman来建立共享的对称密钥,以与诸如AES之类的密码一起使用。在这种情况下,"共享"表示在客户端和服务器之间共享,而不是在所有客户端/用户之间共享。没有硬编码/烘焙密钥。任何地方。 这些键是临时性的,每次用户运行该程序时都会重新生成,或者如果您确实是偏执狂,它们可能会超时并需要重新创建。 计算出的共享秘密对称密钥本身仅存储在内存中的SecureString中。它们很难提取,即使您这样做,它们也只能在很短的时间内发挥作用,并且只能用于特定客户端(即该会话)之间的通信。换句话说,即使有人确实破解了他们的本地密钥,它们也仅会干扰本地通信。他们无法利用这些知识来影响其他用户,这与所有用户通过代码/配置共享的内置密钥不同。 此外,整个密钥本身永远不会通过网络传递。客户端Alice和服务器Bob分别计算它们。理论上,他们为进行此操作而传递的信息可能会被第三方Charlie拦截,从而允许他独立计算共享密钥。这就是为什么您使用那个(明显更昂贵)的非对称PKI来保护Alice和Bob之间的密钥生成的原因。 在这些系统中,密钥生成通常与身份验证以及会话创建结合在一起。您通过PKI进行"登录"并创建"会话",完成之后,客户端和服务器都将独立拥有一个对称密钥,该密钥可用于该会话中所有后续通信的数量级更快的加密。对于大型服务器,这对于通过使用所有内容都使用TLS来节省解密时的计算周期非常重要。 但是等等:我们还没有安全。我们只禁止阅读消息。 请注意,仍然需要使用消息摘要机制来防止中间人操纵。尽管没有人可以读取正在传输的数据,但没有MD,也无法阻止他们修改数据。因此,您可以在加密之前对消息进行哈希处理,然后将哈希值与消息一起发送。然后,服务器在解密时会重新哈希有效负载,并验证它是否与消息中的哈希值匹配。如果邮件在传输过程中被修改,则不会被修改,整个邮件将被丢弃/忽略。 需要防范的最后一种机制是重放攻击。在这一点上,您已经阻止人们读取您的数据以及修改您的数据,但是您并没有阻止他们简单地再次发送数据。如果这对您的应用程序来说是一个问题,则它的协议必须提供数据,并且客户端和服务器都必须具有足够的状态信息才能检测到重放。这可能和作为加密有效载荷一部分的计数器一样简单。请注意,如果您使用的是UDP之类的传输工具,则可能已经有了一种处理重复数据包的机制,因此已经可以应对重放攻击。 显而易见的是,要做到这一点并不容易。因此,除非绝对不能使用PKI,否则请使用PKI。 请注意,这种方法在游戏行业中大量使用,非常需要在每个玩家上花费尽可能少的计算以实现更高的可扩展性,同时提供安全性以防被黑客/撬动。 因此,总而言之,如果这确实是一个值得关注的问题,那么不要尝试找到安全地存储API密钥的方法,而不必这样做。相反,请更改您的应用程序使用此API的方式(假设您自然可以控制双方)。如果PKI太慢(请使用PKI,或者使用PKI共享的对称混合驱动器,那么这会变得非常困难)。这样就不会存储任何与安全有关的问题。 DannySmurf是正确的,您不能向运行应用程序的人员隐藏密钥;如果应用程序可以找到按键,那么人员也可以。 但是,您到底想实现什么? 取决于它的含义,通常有很多方法可以实现您的目标,而不仅仅是依靠在用户的计算机上保留秘密的"秘密"。 我不会这样认为,因为混淆(至少据我理解)会简单地弄乱方法名称,以致于(但并非不可能)理解代码。这不会更改实际密钥的数据(我猜您已将其存储在某个常量中)。 如果只是想让它更难看,则可以对纯文本(例如ROT-13之类)运行简单的密码,以便至少不将其以明文形式存储在代码本身中。但这当然不会阻止任何坚定的黑客访问您的密钥。更加强大的加密方法无济于事,因为您仍然需要在代码中存储THAT的密钥,并且没有任何保护措施。 我能想到的唯一真正安全的事情是将密钥以某种方式保留在应用程序之外,然后限制对密钥的访问。例如,您可以将密钥保存在一个单独的文件中,然后通过基于操作系统级别的基于用户的限制来保护该文件;那可能会工作。您可以对数据库连接执行相同的操作(同样,依靠基于用户的访问限制将未经授权的用户拒之门外)。 我很想为我的应用程序执行此操作,但是我从未实现过。 |