进行 InApp 计费时如何保护 Google Play 公钥

2022-01-20 00:00:00 android google-play java

实际上这对于保护公钥有点傻(那么公钥的定义是什么?)但是根据 Google 提供的文档:

Actually this is a little bit silly about protecting public key (what is the definition of public key then?) but as per the documentation by Google:

为了保护您的公钥免受恶意用户和黑客的攻击,请不要将其作为文字字符串嵌入任何代码中.相反,构建在运行时从片段中提取字符串或使用位操作(例如,与其他字符串异或)以隐藏实际密钥.关键本身是不是秘密信息,但你不想让它变得容易黑客或恶意用户用另一个密钥替换公钥.

To keep your public key safe from malicious users and hackers, do not embed it in any code as a literal string. Instead, construct the string at runtime from pieces or use bit manipulation (for example, XOR with some other string) to hide the actual key. The key itself is not secret information, but you do not want to make it easy for a hacker or malicious user to replace the public key with another key.

有什么推荐的方法吗?

我知道有很多方法可以做到,我只是不想遵循人们过去处理密码散列的方式(例如 md5、sha1 等),我想了解上述用例中的最佳实践.

I know there are many ways to do it, I just don't want to follow the same way how people handle password hashing in the past (e.g. md5, sha1 etc), I want to know the best practice in the above use case.

推荐答案

这在这里出现了很多 :) 您引用的段落背后的想法是,为了确保应用内结算安全,您需要验证交易签名.这些是使用与您的开发者帐户相关联的私钥签名的.密钥位于 Google 的服务器上,因此可以相当安全地假设没有其他人可以用它签署数据.要验证它,您需要您的公钥,您可以从开发者控制台复制它.如果有人在您的应用中替换了它,他们可能会欺骗它接受来自未经授权来源的应用内计费交易,因为如果他们植入公钥,他们可能还会控制相应的私钥.然而,在实践中,简单地在正确的位置修改代码以始终为 isLicensed()hasItem() 或您可能拥有的类似方法返回 true 和没有人这样做.

This comes up a lot around here :) The idea behind the paragraph you are quoting is that for in-app billing to be secure, you need to verify transaction signatures. Those are signed with a private key, associated with your developer account. The key resides on Google's servers, so it's fairly safe to assume that no one else can sign data with it. To verify it you need your public key, which you can copy from the developer console. If someone replaced it in your app, they could fool it to accept in-app billing transactions from unauthorized sources, because if they plant the public key, they probably also control the corresponding private key. In practice however, it is far easier to simply modify your code in the right places to always return true for isLicensed(), hasItem() or similar methods you might have and no one does this.

当然,保护密钥的最佳方法是在您的应用中完全不使用密钥.将所有事务验证逻辑移至您的服务器,并使用 HTTPS 连接到它.正确验证证书链以确保您正在与自己的服务器通信.否则,有人可能会弄乱 DNS 并欺骗您的应用程序连接到他们自己的服务器.几周前宣布了针对 iOS 购买的类似攻击.

The best way to protect the key is, of course, not to have the key in your app at all. Move all of the transaction validation logic to your server, and use HTTPS to connect to it. Properly validate the certificate chain to ensure you are talking to your own server(s). Otherwise, someone might mess around with DNS and fool your app to connect to their own servers. A similar attack against iOS purchasing was announced a couple of weeks ago.

接下来最好的办法是以某种方式混淆密钥,并将其包含在您的应用中.这样做的好处是您不需要服务器,但缺点是如果有人足够坚定,他们会弄清楚的,因为他们总是可以反转您的应用程序的字节码.所以你最好的办法是想出你自己的原始方法来做这件事,不会出现在公共论坛上:) 为了让它更难一点,你可以在本机代码中实现验证部分,这更难(但不是不可能)分析.尽管如此,如上所述,在正确的位置修补字节码比尝试替换公钥要容易得多,因此大多数破解者都会这样做.

The next best thing is to somehow obfuscate the key, and have it included in your app. This has the advantage that you don't need a server, but the disadvantage is that if someone is determined enough they will figure it out, since they can always reverse the byte code of your app. So your best bet is to come up with your own original way to do it that doesn't show up on public forums :) To make it a bit harder, you can implement the validation part in native code, which is harder (but not impossible) to analyze. Still, as mentioned above, patching byte code in the right places is far easier than trying to replace the public key, so that is what most crackers will do.

相关文章