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

时间:2013-01-27 23:26:45

标签: android android-billing

我正在使用应用内结算API的第3版。我有一个单独的,管理的,非消耗品。我还没有在我的应用程序中发布此功能,所以我想在购买之前决定购买有效负载内容。

来自"Security Best Practices"

  

在发出购买请求时设置开发人员有效内容字符串

     

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

     

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

     

当您收到Google Play的回复时,请务必进行验证   开发人员有效内容字符串与您发送的令牌匹配   以前有购买请求。作为进一步的安全   预防措施,您应该自己进行安全验证   服务器

正确或错误,我已决定采取“进一步的安全预防措施”来设置服务器以执行购买验证。而且我没有存储我自己的购买记录 - 我总是称之为计费API。那么我真的有理由进行有效负载验证吗?验证API本身肯定会在报告购买项目之前验证用户的身份,如果攻击者已经破坏了设备(应用程序或Google Play API),我认为没有任何额外检查的好处用户在设备上识别可以轻易绕过的地方。或者有没有理由这样做,我没想到?

8 个答案:

答案 0 :(得分:68)

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

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

因此,简而言之,除非您拥有自己的服务器和特殊的附加逻辑,否则不要使用开发人员有效负载。你应该没问题,只要IAB v3 API能够工作(不幸的是,在这一点上非常大'如果')。

答案 1 :(得分:26)

  

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

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

e.g。

假设我们的应用已登录userA和userB。手机的Android谷歌帐户是X.

  1. userA,登录我们的应用并购买终身会员资格。购买详情存储在Google帐户X下。
  2. userA注销,userB登录我们的应用程序。现在,userB也获得了终身会员的好处,因为Android谷歌帐户仍然是X。
  3. 为避免此类滥用,我们会将购买与帐户绑定。在上面的示例中,我们将在userA进行购买时将开发人员有效负载设置为“userA”。因此,当userB登录时,有效负载将与登录用户(userB)不匹配,我们将忽略购买。因此,userB无法获得userA完成购买的好处。

答案 2 :(得分:21)

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

  
      
  • 警告:开始购买时本地生成随机字符串        在这里验证它似乎是一个很好的方法,但这将失败        用户在一台设备上购买商品然后使用您的应用程序的情况        一个不同的设备,因为在另一台设备上你将无法访问        你最初生成的随机字符串。
  •   

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

答案 3 :(得分:15)

这取决于您验证developerPayload的方式。有两种情况:远程验证(使用服务器)和本地(在设备上)。

服务器

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

MD5(purchaseId + accountId)


设备

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

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

MD5(purchaseId + accountId)


结论

通常情况下,两种情况下的developerPayload可能只是accountId。对我而言,它看起来像security through obscurity。 MD5(或其他哈希算法)和purchaseId只是一种使有效负载更加随机的方法,而不会明确显示我们正在使用帐户的ID。攻击者必须反编译应用程序以检查其计算方式。如果应用程序对您进行了更好的混淆。

有效负载不提供任何安全性。用“设备”可以很容易地欺骗它。在服务器'中抓住方法而不费力检查。请务必使用Google发布商帐户控制台中提供的公钥实施签名检查。

*有关使用帐户ID而不是电子邮件的must-read博文。

答案 4 :(得分:5)

在关于IAB v3的Google IO视频中,由琐碎的驱动器样本的作者自己提供,这是在视频结束时简要说明的。它可以防止重放攻击,例如:攻击者嗅探流量,窃取包含成功购买的数据包,然后尝试在自己的设备上重播数据包。如果您的应用在发布优质内容(最好是来自您的服务器)之前未通过dev有效负载(最好是在您的服务器上)检查买方的身份,则攻击者将成功。由于数据包完好无损,签名验证无法检测到这一点。

在我看来,这种保护似乎非常适合具有在线帐户连接的应用程序,如部落冲突(有效载荷自然而然,因为你必须识别用户),特别是在黑客攻击多人游戏玩法时,除了简单的本地化之外还有远程影响盗版案。相比之下,如果apk上的客户端黑客已经解锁了高级内容,那么这种保护就不是很有用了。

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

答案 5 :(得分:3)

我挣扎着这个。由于Google Play帐户只能拥有任何“托管”商品中的一个,但可能有多个设备(我有三个),上述评论来自某人,您销售的“每台设备”将无效......他们会能够把它放在他们的第一台设备上,而不是其他任何设备...如果您购买了高级升级版,它应该适用于您的所有手机/平板电脑。

我鄙视获取用户电子邮件地址的概念,但我发现没有其他可靠的方法。所以我抓住了帐户列表中匹配“google.com”的第一个帐户(是的,添加到您的清单的权限),然后立即哈希,以便它不再可用作电子邮件地址,但提供“足够独特” “令牌。这就是我发送的Payload。由于大多数人使用Google Play ID激活他们的设备,因此所有三个设备都会得到相同的令牌(在每个设备上使用相同的哈希算法)。

它甚至适用于具有多个“用户”的KitKat。 (我的开发人员ID在一个用户上,我的测试ID在另一个用户上,每个用户在他们自己的沙箱中)。

我在六台设备上测试了它,共有3个用户,每个用户设备都返回了相同的哈希值,不同的用户都有不同的哈希值,符合指南。

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

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

答案 6 :(得分:3)

2018年末更新:官方Google Play计费库有意不公开developerPayload。来自here

  

字段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)。

答案 7 :(得分:1)

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

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

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

此致

圣地亚哥