实际上,这对于保护公钥有点愚蠢(那么公钥的定义是什么?),但根据Google 的文档:
为了保护您的公钥免受恶意用户和黑客的攻击,请勿将其作为文字字符串嵌入任何代码中。相反,在运行时从片段构造字符串或使用位操作(例如,与其他字符串进行异或)来隐藏实际密钥。密钥本身不是秘密信息,但您不想让黑客或恶意用户轻易地用另一个密钥替换公钥。
有什么推荐的方法吗?
我知道有很多方法可以做到这一点,我只是不想遵循人们过去处理密码哈希的方式(例如 md5、sha1 等),我想知道上述用例中的最佳实践。
实际上,这对于保护公钥有点愚蠢(那么公钥的定义是什么?),但根据Google 的文档:
为了保护您的公钥免受恶意用户和黑客的攻击,请勿将其作为文字字符串嵌入任何代码中。相反,在运行时从片段构造字符串或使用位操作(例如,与其他字符串进行异或)来隐藏实际密钥。密钥本身不是秘密信息,但您不想让黑客或恶意用户轻易地用另一个密钥替换公钥。
有什么推荐的方法吗?
我知道有很多方法可以做到这一点,我只是不想遵循人们过去处理密码哈希的方式(例如 md5、sha1 等),我想知道上述用例中的最佳实践。
这在这里出现了很多 :) 您引用的段落背后的想法是,为了确保应用内结算安全,您需要验证交易签名。这些是使用与您的开发者帐户相关联的私钥签名的。密钥位于 Google 的服务器上,因此可以相当安全地假设没有其他人可以用它签署数据。要验证它,您需要您的公钥,您可以从开发者控制台复制它。如果有人在您的应用中替换了它,他们可能会欺骗它接受来自未经授权来源的应用内计费交易,因为如果他们植入公钥,他们可能还会控制相应的私钥。然而,在实践中,简单地在正确的位置修改代码以始终返回 true for或您可能拥有的类似方法要容易得多isLicensed()
,hasItem()
而没有人这样做。
当然,保护密钥的最佳方法是在您的应用程序中完全不使用密钥。将所有事务验证逻辑移至您的服务器,并使用 HTTPS 连接到它。正确验证证书链以确保您正在与自己的服务器通信。否则,有人可能会弄乱 DNS 并欺骗您的应用程序连接到他们自己的服务器。几周前宣布了针对 iOS 购买的类似攻击。
下一个最好的办法是以某种方式混淆密钥,并将其包含在您的应用程序中。这样做的好处是您不需要服务器,但缺点是如果有人足够坚定,他们会弄清楚的,因为他们总是可以反转您的应用程序的字节码。所以你最好的办法是想出你自己的原始方法来做这件事,不会出现在公共论坛上:) 为了让它更难一点,你可以在本机代码中实现验证部分,这更难(但不是不可能)分析。尽管如此,如上所述,在正确的位置修补字节码比尝试替换公钥要容易得多,因此大多数破解者都会这样做。
至少做简单的文本转换。这个想法是普通的 dex 反汇编不会泄露你的公钥。
这是进行简单字符串编码/解码的函数示例:
/**
* Simple String transformation by XOR-ing all characters by value.
*/
static String stringTransform(String s, int i) {
char[] chars = s.toCharArray();
for(int j = 0; j<chars.length; j++)
chars[j] = (char)(chars[j] ^ i);
return String.valueOf(chars);
}
然后您的私钥作为编码字符串存储在源中(使用此函数对其进行编码),并在运行时使用相同的函数进行解码。这是谷歌建议的一种“异或”方法。
你自己制作'i'参数,任何随机的东西,如0x27或其他都可以。如果您以这种方式隐藏更多字符串,请为每个转换使用不同的“i”。
将您的公钥存储在服务器端,一旦您从 google play 获得响应以验证密钥,就会将该响应发送到服务器并在服务器上执行您的操作。
公钥是 base64 编码的 ( [a-zA-Z0-9+/]
),因此您可以轻松避免需要转义混淆字符串,因为这是 @PointerNull 解决方案中的一个烦人问题。
相反,您可以通过首先将相关字符转换为 6 位 int 来执行混淆。然后进行位操作(例如 XOR-ing),然后转换回 base64 编码的字符。保证不需要字符转义。