78

我正在使用第 3 版的应用内计费 API。我有一个单一的、托管的、非消耗品。我还没有在我的应用程序中发布这个功能,所以我想在购买之前决定购买有效载荷的内容。

来自“安全最佳实践”

发出购买请求时设置开发者有效负载字符串

使用 In-app Billing Version 3 API,您可以在向 Google Play 发送购买请求时包含一个“开发者有效负载”字符串令牌。通常,这用于传递唯一标识此购买请求的字符串令牌。如果您指定字符串值,Google Play 会将此字符串与购买响应一起返回。随后,当您查询此次购买时,Google Play 会返回此字符串以及购买详情。

您应该传入一个字符串令牌,以帮助您的应用程序识别进行购买的用户,以便您以后可以验证这是该用户的合法购买。对于消耗品,您可以使用随机生成的字符串,但对于非消耗品,您应该使用唯一标识用户的字符串。

当您从 Google Play 收到响应时,请确保验证开发人员有效负载字符串与您之前随购买请求发送的令牌匹配。作为进一步的安全预防措施,您应该在自己的安全服务器上执行验证。

对或错,我决定采取设置服务器进行购买验证的“进一步安全预防措施”。而且我不存储自己的购买记录——我总是调用计费 API。那么我真的有任何理由进行此有效负载验证吗?验证 API 本身肯定会在将商品报告为已购买之前验证用户的身份,如果攻击者入侵了设备(应用程序或 google play API),我看不出进行额外检查有什么好处用户在设备上的标识,很容易被绕过。还是有我没有想到的这样做的理由?

4

8 回答 8

70

如果您不保留记录,则无法验证您收到的内容是否就是您发送的内容。因此,如果您将某些内容添加到开发人员有效负载中,您可以相信它是合法的(如果签名验证,这是一个合理的假设),或者不完全信任它并且仅将其用作参考,但不能用于验证许可证状态等. 例如,如果您存储用户电子邮件,您可以使用该值而不是要求他们再次输入它,这对用户来说稍微友好一些,但如果它不存在,您的应用程序不会中断。

就个人而言,我认为整个“最佳实践”部分令人困惑,并且试图让您做 API 真正应该做的工作。由于购买与 Google 帐户相关联,并且 Play 商店显然会保存此信息,因此他们应该在购买详细信息中为您提供此信息。获取正确的用户 ID 需要额外的权限,您不需要添加这些权限只是为了弥补 IAB API 的缺陷。

因此,简而言之,除非您有自己的服务器和特殊的附加逻辑,否则不要使用开发人员有效负载。你应该没问题,只要 IAB v3 API 有效(不幸的是,此时这是一个很大的“如果”)。

于 2013-01-28T01:51:46.143 回答
30

您应该传入一个字符串令牌,以帮助您的应用程序识别进行购买的用户...

如果您的应用程序提供自己的用户登录名和身份,这与手机所连接的 Google 帐户不同,那么您需要使用开发人员有效负载将购买附加到您进行购买的帐户之一。否则,有人可能会在您的应用中切换帐户,并从购买的东西中受益。

例如

假设我们的应用程序有用户 A 和用户 B 的登录名。而手机的安卓谷歌账号是X。

  1. userA,登录我们的应用程序并购买生活会员。购买详情存储在谷歌账户 X 下。
  2. userA 退出,userB 登录到我们的应用程序。现在,userB 也获得了终身会员的福利,因为 android google 帐号仍然是 X。

为避免此类滥用,我们会将购买绑定到一个帐户。在上面的示例中,我们将在 userA 进行购买时将开发人员有效负载设置为“userA”。因此,当用户 B 登录时,有效负载将与登录用户 (userB) 不匹配,我们将忽略购买。因此,用户B 无法从用户A 的购买中获得收益。

于 2013-05-04T06:37:17.263 回答
21

开发人员有效负载处理还有另一种方法。正如 Nikolay Elenkov 所说,要求用户 ID 和为您的应用程序设置用户配置文件的额外权限的开销太大,所以这不是一个好方法。因此,让我们看看 Google 在 In-App Billing v3 示例中最新版本的 TrivialDrive 示例应用中所说的内容:

  • 警告:在开始购买时本地生成随机字符串并在此处进行验证似乎是一种好方法,但如果用户在一台设备上购买商品然后在另一台设备上使用您的应用程序,这将失败,因为在您将无法访问您最初生成的随机字符串的其他设备。

因此,如果您要在另一台设备上验证购买的商品,随机字符串不是一个好主意,但他们仍然没有说这不是验证购买响应的好主意。我想说 - 仅使用开发人员有效负载通过发送随机唯一字符串来验证购买,将其保存在首选项/数据库中,并在购买响应中检查此开发人员有效负载。至于在活动开始时查询库存(应用内购买) - 不要费心检查开发人员有效负载,因为这可能发生在您没有存储随机唯一字符串的另一台设备上。我就是这么看的。

于 2013-03-26T15:38:05.130 回答
16

这取决于您如何验证developerPayload. 有两种场景:远程验证(使用服务器)和本地(在设备上)。

服务器

如果您使用服务器进行developerPayload验证,它可以是可以在设备和服务器上轻松计算的任意字符串。您应该能够识别执行请求的用户。假设每个用户都有对应accountId的 ,developerPayload可以purchaseId像这样与 (SKU name) 组合计算:

MD5(purchaseId + accountId)


设备

developerPayload 不应该是用户电子邮件。Google for Work 服务就是您不应使用电子邮件作为有效负载的一个很好的例子。用户可以更改与该帐户关联的电子邮件。唯一不变的是accountId。在大多数情况下,电子邮件是可以的(例如,Gmail 地址目前是不可变的),但请记住为未来设计。

多个用户可能使用同一设备,因此您必须能够区分谁是该项目的所有者。对于设备验证developerPayload,是一个唯一标识用户的字符串,例如:

MD5(purchaseId + accountId)


结论

通常,developerPayload在这两种情况下可能只是accountId. 对我来说,它看起来像是默默无闻的安全。MD5(或其他散列算法)purchaseId只是一种使有效负载更加随机的方法,而无需明确显示我们正在使用帐户的 id。攻击者必须反编译应用程序以检查其计算方式。如果应用程序被混淆,对你来说更好。

有效载荷不提供任何安全性。它可以很容易地通过“设备”方法进行欺骗,而无需在“服务器”检查中进行任何努力。请记住使用您在 Google Publisher 帐户控制台中提供的公钥来实施签名检查。

*关于使用帐户 ID 而非电子邮件的必读博文。

于 2014-12-01T10:45:14.720 回答
5

2018 年末更新:官方 Google Play 计费库有意不公开developerPayload. 从这里

字段 developerPayload 是一个遗留字段,保持与旧实现的兼容性,但如购买应用内计费产品页面(https://developer.android.com/training/in-app-billing/purchase-iab )所述-products.html),在完成与应用内结算相关的任务时,此字段并不总是可用。由于该库旨在代表最新的开发模型,因此我们决定在我们的实现中不支持 developerPayload,并且我们没有计划将此字段包含到库中。

如果您将应用内计费逻辑的任何重要实现依赖于 developerPayload,我们建议您更改此方法,因为此字段将在某个时候(或很快)被弃用。推荐的方法是使用您自己的后端来验证和跟踪有关您的订单的重要详细信息。有关更多详细信息,请查看安全和设计页面 ( https://developer.android.com/google/play/billing/billing_best_practices.html )。

于 2018-11-06T01:06:00.987 回答
5

在琐碎驱动器示例的作者本人提供的有关 IAB v3 的 Google IO 视频中,在视频结尾处简要介绍了这一点。这是为了防止重放攻击,例如攻击者嗅探流量,窃取包含成功购买的数据包,然后尝试在自己的设备上重放数据包。如果您的应用在发布高级内容(也最好是从您的服务器上)之前没有通过开发负载(理想情况下在您的服务器上)检查买家的身份,那么攻击者就会成功。签名验证无法检测到这一点,因为数据包是完整的。

在我看来,这种保护似乎非常适合具有在线帐户连接的应用程序,例如部落冲突(有效负载自然会出现,因为无论如何您都必须识别用户),尤其是在黑客破坏多人游戏玩法的情况下,除了简单的本地化盗版案例外,还具有深远的影响. 相反,如果客户端对 apk 的黑客攻击已经可以解锁高级内容,那么这种保护就不是很有用了。

(如果攻击者试图欺骗有效载荷,签名验证应该会失败)。

于 2016-03-16T07:46:20.127 回答
3

我与这个斗争。由于 Google Play 帐户只能拥有任何“托管”项目中的一个,但可以拥有多个设备(我有三个),因此您出售“每个设备”的上述评论将不起作用......他们会能够将它放在他们的第一台设备上,而其他任何设备都没有......如果您购买高级升级,它应该可以在您的所有手机/平板电脑上使用。

我鄙视获取用户电子邮件地址的想法,但我真的没有找到其他可靠的方法。因此,我在帐户列表中获取与“google.com”匹配的第一个帐户(是的,添加到您的清单的权限),然后立即对其进行哈希处理,使其不再可用作电子邮件地址,但确实提供了“足够独特“令牌。这就是我作为开发人员有效负载发送的内容。由于大多数人使用他们的 Google Play id 激活他们的设备,因此很可能所有三个设备都将获得相同的令牌(在每个设备上使用相同的哈希算法)。

它甚至可以在具有多个“用户”的 KitKat 上运行。(我的开发者 ID 在一个用户上,我的测试 ID 在另一个用户上,每个用户都在自己的沙箱中)。

我已经在总共 3 个用户的六台设备上对其进行了测试,每个用户的设备都返回了相同的哈希值,并且不同的用户都有不同的哈希值,满足了指导方针。

我绝不会存储用户的电子邮件地址,它直接从代码中传递以获取帐户名称到哈希函数,并且只有哈希值保存在堆中。

可能还有更好的解决方案,更加尊重用户隐私,但到目前为止我还没有找到。一旦应用程序发布,我将非常清楚地说明我如何在我的隐私政策中使用用户电子邮件地址。

于 2014-03-06T04:11:11.337 回答
1

这通常响应产品定义(您的应用程序)。例如订阅的情况。同一用户能否在他/她拥有的所有设备上使用订阅?如果答案是肯定的。我们没有检查有效载荷。

对于消耗品。假设您的应用程序中的一次购买给了您 10 个虚拟硬币。用户能否在不同的设备上使用这些硬币?一台设备上 4 个,另一台设备上 6 个?如果我们只想在购买的设备上工作,我们必须检查有效负载,例如使用自行生成的字符串并在本地存储。

基于这些问题,我们必须决定如何实施有效载荷检查。

问候

圣地亚哥

于 2017-03-24T22:36:11.610 回答