为什么使用应用内结算来设置开发人员有效负载很重要?

我正在使用应用内结算API的版本3。 我有一个单独的,pipe理的,非消耗品。 我还没有在应用中发布这个function,所以我想在购买之前决定购买有效载荷的内容。

从“安全最佳实践” :

进行购买请求时设置开发人员负载string

使用应用内结算版本3 API时,您可以在向Google Play发送购买请求时添加“开发者有效负载”string标记。 通常,这用于传递唯一标识此购买请求的string标记。 如果您指定string值,则Google Play会将此string与购买回复一起返回。 随后,当您对此购买进行查询时,Google Play会将此string与购买详细信息一起返回。

您应该传入一个string标记,以帮助您的应用程序标识进行购买的用户,以便您稍后可以validation该用户是否合法购买。 对于消耗品,您可以使用随机生成的string,但对于非消耗品,您应该使用唯一标识用户的string。

当您收回Google Play的响应时,请确保validation开发者有效负载string与之前通过购买请求发送的令牌相匹配。 作为进一步的安全防范措施,您应该在您自己的安全服务器上执行validation。

无论对错,我都决定采取build立服务器进行购买validation的“进一步安全防范”。 而且我不存储我自己的购买logging – 我总是调用计费API。 那么真的有什么理由要做这个有效载荷validation吗? validationAPI本身在报告购买物品之前肯定会validation用户的身份,并且如果攻击者已经泄露了设备(应用程序或Google Play API),我认为没有任何好处用户在设备上可以很容易地避开的标识。 还是有理由这样做,我没有想到?

如果您没有保存logging,则无法validation您获得的是您发送的内容。 因此,如果您向开发人员有效内容添加了某些内容,您可以相信它是合法的(签名validation时这是一个合理的假设),或者完全不信任它,只使用它作为引用,但不用于validation许可证状态等。例如,如果您存储了用户电子邮件,则可以使用该值而不是让他们再次input该值,这比用户友好一些,但如果不存在,您的应用程序不会中断。

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

所以,总之,除非你有自己的服务器和特殊的附加逻辑,否则就不要使用开发人员负载。 只要IAB v3 API有效(不幸的是,在这一点上,这是一个相当大的“如果”),你应该没问题。

您应该传入一个string标记,以帮助您的应用程序识别进行购买的用户。

如果您的应用程序提供了自己的用户login信息和身份信息(与电话所连接的Google帐户不同),那么您需要使用开发人员有效负载将购买行为附加到进行购买的其中一个帐户。 否则,有人可以在您的应用程序切换帐户,并获得购买的东西的好处。

例如

假设我们的应用程序已经login了userA和userB。 而手机的Android谷歌帐户是X.

  1. userA,login到我们的应用程序,并购买人生成员。 购买细节存储在谷歌账户X下。
  2. 用户A注销,用户Blogin到我们的应用程序。 现在,用户B也得到了生活会员的好处,因为Android的谷歌帐户仍然是X.

为了避免这种滥用,我们会将购买与帐户绑定。 在上面的例子中,当用户A进行购买时,我们将开发者负载设置为“userA”。 因此,当用户Blogin时,有效载荷将不匹配login用户(用户B),我们将忽略购买。 因此,userB无法获得由userA完成的购买的好处。

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

  • 警告:在本地生成一个随机string,当在这里开始一个购买和validation它可能看起来像一个好方法,但是当用户在一个设备上购买一个项目,然后在另一个设备上使用你的应用程序,这将失败,因为另一个设备你将不能访问你最初生成的随机string。

因此,如果您要validation其他设备上购买的商品,那么随机string并不是一个好主意,但是他们并不认为这不是validation购买回复的好主意。 我会说 – 只使用开发人员有效负载通过发送一个随机的唯一stringvalidation购买,保存在首选项/数据库和购买响应检查此开发人员的有效负载。 至于查询活动开始的库存(应用程序内购买) – 不要检查开发人员的有效负载,因为这可能发生在另一个设备,你没有随机唯一的string存储。 这就是我所看到的。

这取决于你如何validationdeveloperPayload 。 有两种情况:远程validation(使用服务器)和本地(在设备上)。

服务器

如果您使用服务器进行developerPayloadvalidation,则它可以是任意string,可以在设备和服务器上轻松计算。 您应该能够识别执行请求的用户。 假设每个用户都有相应的accountIddeveloperPayload可以计算为与purchaseId (SKU名称)的组合,如下所示:

 MD5(purchaseId + accountId) 

设备

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

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

 MD5(purchaseId + accountId) 

结论

一般来说,这两种情况下的developerPayload可能只是accountId 。 对我来说,它看起来像安全通过默默无闻 。 MD5(或其他哈希algorithm)和purchaseId只是一种使得有效载荷更加随机的方式,而不明确地显示我们使用的是账户的id。 攻击者将不得不反编译应用程序来检查它是如何计算的。 如果应用程序被混淆了,甚至更好。

有效载荷不提供任何安全性 。 它可以很容易地欺骗'设备'的方法,没有任何努力抓住'服务器'检查。 请记住使用Google发布商帐户控制台中提供的公钥进行签名检查。

*有关使用帐户ID而不是电子邮件的必读博客文章。

在关于IAB v3的Google IOvideo中,我们简单介绍了这个video的结尾,然后简要介绍了这个video。 这是为了防止重放攻击,例如攻击者嗅探stream量,窃取包含成功购买的数据包,然后试图在自己的设备上重放数据包。 如果您的应用程序在发布优质内容之前(最好从您的服务器上)没有通过开发负载(最好在您的服务器上)检查买方的身份,则攻击者将成功。 由于数据包完好无损,因此签名validation无法检测到此情况。

在我看来,这种保护似乎是理想的应用程序与在线帐户连接像部族冲突(有效载荷自然而然,因为你必须确定用户无论如何),尤其是在黑客入侵多人游戏的影响远远不仅仅是一个简单的本地化的盗版案件。 相反,如果apk上的客户端黑客已经可以解锁优质内容,那么这种保护并不是很有用。

(如果攻击者试图欺骗有效负载,则签名validation将失败)。

我为此而挣扎。 由于Google Play帐户只能拥有任何“托pipe”商品中的一个,但可能有多个设备(我有三个),所以上述有关您销售“每台设备”的评论将无法使用……他们会能够把它放在他们的第一个设备,并没有其他人…如果你购买了一个高级升级,它应该适用于所有的手机/平板电脑。

我鄙视收到用户的电子邮件地址的概念,但我真的没有发现其他可靠的方法。 所以我在账户列表中find与“google.com”相匹配的第一个账户(是的,这是一个添加到你的清单中的权限),然后立即对它进行哈希以使其不再可用作为电子邮件地址,但确实提供了“ “令牌。 这就是我发送的开发人员负载。 由于大多数人用他们的Google Play ID激活他们的设备,所以三个设备都有相同的标记(在每个设备上使用相同的散列algorithm)。

它甚至可以在具有多个“用户”的KitKat上工作。 (我的开发者ID是在一个用户上,我的testingID在另一个用户上,每个用户在他们自己的沙箱中)。

我已经通过六个设备testing了它,总共有三个用户,每个用户设备都返回了相同的哈希值,不同的用户都有不同的哈希值,符合指导原则。

在任何时候我都不会存储用户的电子邮件地址,而是直接从代码中获取帐户名称以获得散列函数,只有散列保存在堆中。

可能还有一个更好的解决scheme,更尊重用户的隐私,但到目前为止我还没有find它。 一旦应用程序发布,我将对如何在隐私策略中使用用户电子邮件地址做出非常明确的描述。

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

用于消耗品。 假设在你的应用程序中购买了10个虚拟硬币。 用户是否可以在不同的设备上使用这些硬币? 4在一个设备上,6在另一个? 如果我们只想在购买的设备上工作,那么我们必须检查有效载荷,例如使用自生string并且本地存储。

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

问候

圣地亚哥