IAP交易的验证踩坑总结

达芬奇密码2018-07-03 09:46
前言
目前各个APP的IOS客户端应该都有应用内购买(IAP),关于IAP的交互流程,就不赘述了,放一张图就行

作为服务端开发,关注的步骤就是 11 12 13
也就是苹果应用内购买的凭证验证过程,没有严格验证,导致了一个比较大的坑

现场
某一日,产品老大发现近两天的IAP的交易金额突然涨了很多,觉得有点问题,于是过来询问,当时的我怎么可能会有问题,我都是和苹果服务器验证返回成功才将交易处理为成功的

调试
随机找了一个交易的凭证,和苹果服务端进行验证,发现返回结果如下:
{
  "status": 0,
  "environment": "Production",
  "receipt": {
    "receipt_type": "Production",
    "adam_id": 958907096,
    "app_item_id": 958907096,
    "bundle_id": "com.netease.xxxxxx",
    "application_version": "1.5.1",
    "download_id": 97014364696609,
    "version_external_identifier": 817854011,
    "receipt_creation_date": "2016-07-08 03:42:22 Etc/GMT",
    "receipt_creation_date_ms": "1467949342000",
    "receipt_creation_date_pst": "2016-07-07 20:42:22 America/Los_Angeles",
    "request_date": "2016-07-13 07:24:39 Etc/GMT",
    "request_date_ms": "1468394679624",
    "request_date_pst": "2016-07-13 00:24:39 America/Los_Angeles",
    "original_purchase_date": "2016-07-08 03:42:22 Etc/GMT",
    "original_purchase_date_ms": "1467949342000",
    "original_purchase_date_pst": "2016-07-07 20:42:22 America/Los_Angeles",
    "original_application_version": "1.5.1",
    "in_app": [
      
    ]
  }
}
乍一看,没有任何问题啊,我们验证方案也非常的简单,根据凭证验证的返回的结果,用 bundle_id 和 我们app的bundleid进行比较,如果一致就认为验证通过(现在想想,验证方案实在太简单了

然后找了之前的凭证数据,进行验证,返回结果如下:
{
  "status": 0,
  "environment": "Production",
  "receipt": {
    "receipt_type": "Production",
    "adam_id": 958907096,
    "app_item_id": 958907096,
    "bundle_id": "com.netease.xxxxx",
    "application_version": "1.5.1",
    "download_id": 91010193845861,
    "version_external_identifier": 817854011,
    "receipt_creation_date": "2016-07-05 14:09:42 Etc/GMT",
    "receipt_creation_date_ms": "1467727782000",
    "receipt_creation_date_pst": "2016-07-05 07:09:42 America/Los_Angeles",
    "request_date": "2016-07-13 06:00:38 Etc/GMT",
    "request_date_ms": "1468389638110",
    "request_date_pst": "2016-07-12 23:00:38 America/Los_Angeles",
    "original_purchase_date": "2016-03-27 05:22:52 Etc/GMT",
    "original_purchase_date_ms": "1459056172000",
    "original_purchase_date_pst": "2016-03-26 22:22:52 America/Los_Angeles",
    "original_application_version": "1.3.3",
    "in_app": [
      {
        "quantity": "1",
        "product_id": "com.netease.xxxxx.baoyue_3002_PHO",
        "transaction_id": "510000114309436",
        "original_transaction_id": "510000114309436",
        "purchase_date": "2016-03-27 07:47:24 Etc/GMT",
        "purchase_date_ms": "1459064844000",
        "purchase_date_pst": "2016-03-27 00:47:24 America/Los_Angeles",
        "original_purchase_date": "2016-03-27 07:47:24 Etc/GMT",
        "original_purchase_date_ms": "1459064844000",
        "original_purchase_date_pst": "2016-03-27 00:47:24 America/Los_Angeles",
        "is_trial_period": "false"
      },
      {
        "quantity": "1",
        "product_id": "com.netease.xxxxx.baoyue_3002_PHO",
        "transaction_id": "510000126047956",
        "original_transaction_id": "510000126047956",
        "purchase_date": "2016-07-05 14:09:42 Etc/GMT",
        "purchase_date_ms": "1467727782000",
        "purchase_date_pst": "2016-07-05 07:09:42 America/Los_Angeles",
        "original_purchase_date": "2016-07-05 14:09:42 Etc/GMT",
        "original_purchase_date_ms": "1467727782000",
        "original_purchase_date_pst": "2016-07-05 07:09:42 America/Los_Angeles",
        "is_trial_period": "false"
      }
    ]
  }
}
注意一下红色的部分,正常的凭证in_app里会有数据的,而非法的凭证验证凭证结果这个字段的数据是空的
问题
非法的凭证是怎么产生的?---越狱机器进行篡改?(这个尝试过,没有成功,已经提交给信息安全部)
苹果服务端为什么可以通过验证?----这个也不知道为什么可以通过,也没有查到这方面的资料
我们的验证方案是不是太简单了?---答案是肯定的,不知道是怎么产生,也不知道苹果为什么可以通过验证,能做的就是自己加强结果验证

验证改进
1.in_app不能为空
2.in_app内的订单信息的交易id,产品id,必须和客户端上报的信息一致,否则认为非法

结语
验证方案尽量完整,不要只简单验证,即使凭证是通过了苹果服务端的验证

参考:
https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW12

本文来自网易实践者社区,经作者方向授权发布。