进行InApp结算时如何保护Google Play公钥

时间:2012-07-26 14:44:12

标签: java android google-play

实际上这对于保护公钥有点愚蠢(那么公钥的定义是什么?)但是根据documentation by Google

  

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

有推荐的方法吗?

我知道有很多方法可以做到这一点,我只是不想按照人们处理密码哈希过去的方式(例如md5,sha1等),我想了解上述用例中的最佳实践。

5 个答案:

答案 0 :(得分:37)

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

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

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

答案 1 :(得分:32)

至少进行简单的文本转换。我们的想法是,普通的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);
}

然后您的私钥作为编码字符串存储在源中(使用此函数对其进行编码),并在运行时使用相同的函数进行解码。这是Google建议的一种“XOR”方法。

你自己制作'i'参数,任何随机的东西,如0x27或其他都可以。 如果您以这种方式隐藏更多字符串,请为每个转换使用不同的“i”。

答案 2 :(得分:11)

作为手动混淆密钥的替代方法,您也可以让混淆器自动执行此操作。 ProGuard是Android SDK的一部分,但它主要模糊了类/字段/方法名称,而不是字符串。它的Android专用兄弟DexGuard可以添加更多层混淆,应用字符串加密,类加密和反射。它不是免费的,但它可以节省时间,而且可能比手动操作更有效。

(我是ProGuard和DexGuard的开发者)

答案 3 :(得分:4)

将您的公钥存储在服务器端,一旦您从Google Play获得响应,就会验证该密钥是否将该响应发送到服务器并在服务器上执行您的操作。

答案 4 :(得分:1)

公钥是base64编码的([a-zA-Z0-9+/]),因此您可以轻松地避免需要转义混淆的字符串,这是@ PointerNull解决方案中的烦人问题。

相反,您可以通过首先将有问题的字符转换为6位int来执行混淆。然后进行位操作(例如XOR-ing),然后转换回base64编码的char。保证不需要逃脱角色。