1. 客户端直接verify苹果的receipt 如果verify成功 自行发放商品

2. 客户端将receipt传给server,由server进行验证并发放商品

按照安全性原则, 客户端的所有信息都是不可信的,而且支付是业务中的核心模块,所以应该选择第二种。

下面简要介绍下,第二种方式的简单流程。

1. 客户端支付成功,拿到receipt

2. 客户端将receipt传到服务端

3. 服务端去apple验证receipt 如果验证成功 就发放receipt中的商品

支付安全性

作为支付,安全性是第一位的,下面简要分析一下常用的攻击手段。

1、劫持apple server攻击 => 通过dns污染,让客户端支付走到假的apple_server,并返回验证成功的response。 这个主要针对支付方式一 如果是支付方式二 就无效。

2、重复验证攻击 => 一个receipt重复使用多次

3、跨app攻击 => 别的app的receipt用到我们app中来

4、换价格攻击 => 低价商品代替高价商品

5、歧义攻击 => iap支付之前的status=0表示verify成功 而现在变为status=0只能表示receipt合法 具体支付详情需要通过in_app字段决定 For iOS 6 style transaction receipts, the status code reflects the status of the specific transaction’s receipt.

6、中间人攻击 => 伪造apple_server,如果用户支付就将

劫持apple server攻击

通过dns污染,让客户端通过假的apple_server进行verify,从而认为自己支付成功。这个主要针对**支付方式一**,如果是支付方式二,就没效果了。常见的iap hack软件@iAPFree @iAP Cracker 就是用的类似原理。

重复验证攻击

因为同一个receipt,如果第一次验证成功,那么之后每次验证都会成功。如果服务端没有判重机制,就会导致一个receipt被当做多次充值处理。

为了预防这种情况,我们可以将receipt做一次md5得到receipt_md5, 每次发送充值请求的时候就按照receipt_md5判重,如果重复就停止商品发放。

app攻击

通过在别的app中拿到receipt,然后发送到我们app中。因为这个receipt是合法的而且apple不会验证请求的源,所以这个receipt是可以验证通过的。

对于这种情况,我们可以判断apple verify的返回值apple_callback_data中对应的bundle_id和我们app的bundle_id是否一样来进行验证。

换价格攻击

在同一个app中,用低价商品的receipt伪造购买高价商品。这时候bundle_id和我们app的bundle_id是一致的。

针对这种情况, 我们可以从apple verify的返回值apple_callback_data中拿到对应的PRoduct_id, 并按照product_id来进行充值。 **不要信任客户端的product_id**

歧义攻击

在iOS6的时候,status=0表示此次支付成功,而现在变为status=0只表示receipt**整体上**合法。

所以,对iOS7即使是一个过期订单,也会返回status=0,如果还按照iOS6的逻辑处理,就会导致假充值。针对iOS7,我们应该不只通过status,还要通过in_app中的内容,来决定如何发放商品。

```

For iOS 6 style transaction receipts, the status code reflects the status of the specific transaction’s receipt.

For iOS 7 style app receipts, the status code is reflects the status of the app receipt as a whole. For example, if you send a valid app receipt that contains an expired subscription, the response is 0 because the receipt as a whole is valid.

中间人攻击

伪造apple server,将我们的支付请求转发到真的apple_server,拿到合法的receipt,并弄个假的receipt给客户端。这样就拿到一个合法的凭证。利用这个合法的receipt,伪造别人充值的请求,从而达到帮别人充值的目的。

针对中间人攻击,最重要的是保证a用户的支付receipt,不能被b用户使用。但是apple为了保护隐私,receipt中没有任何用户的个人信息,这就需要我们自己来保证。目前我们用加密的手段来做这个保证。

iOS支付的详细流程

客户端拿到apple的receipt 并发送到serverserver拿到这个receipt,向苹果验证得到apple_callback_data如果apple_callback_data的status是21007,说明是沙盒模式(不用花钱就可以购买) 要根据具体需求判断处理逻辑,需要注意的是,ios的审核在支付的时候就采用的沙盒模式。

如果apple_callback_data的status是0,就要从apple_callback_data[‘receipt’][‘in_app’]这个list中拿到所有的记录,每一个进行充值。然后记录transaction_id和original_transaction_id来防止同一个transaction被重复使用。

https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Restoring.html

https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1 => Original Transaction Identifier

返回所有充值成功和重复的transaction_id, 有client来complete transaction

总结

支付作为核心模块,除了技术上的保证,商务也应该每周进行一次对账。如果发现apple上的收入和服务端记录的收入有比较大的差距,就应该抓紧查看原因。

最后给出一个apple_callback_data的例子

{

"status": 0,

"environment": "Production",

"receipt": {

"download_id": 75017873837267,

"adam_id": 1149703708,

"request_date": "2017-01-13 06:57:20 Etc/GMT",

"app_item_id": 1149703708,

"original_purchase_date_pst": "2016-11-17 18:57:09 America/Los_Angeles",

"version_external_identifier": 820252187,

"receipt_creation_date": "2017-01-13 05:04:52 Etc/GMT",

"in_app": [

{

"is_trial_period": "false",

"purchase_date_pst": "2017-01-12 21:04:52 America/Los_Angeles",

"original_purchase_date_pst": "2017-01-12 21:04:52 America/Los_Angeles",

"product_id": "com.lucky917.live.gold.1.555",

"original_transaction_id": "350000191094279",

"original_purchase_date": "2017-01-13 05:04:52 Etc/GMT",

"original_purchase_date_ms": "1484283892000",

"purchase_date": "2017-01-13 05:04:52 Etc/GMT",

"purchase_date_ms": "1484283892000",

"transaction_id": "350000191094279",

"quantity": "1"

}

],

"original_purchase_date_ms": "1479437829000",

"original_application_version": "26",

"original_purchase_date": "2016-11-18 02:57:09 Etc/GMT",

"request_date_ms": "1484290640800",

"bundle_id": "com.lucky917.ios.Live",

"receipt_creation_date_pst": "2017-01-12 21:04:52 America/Los_Angeles",

"application_version": "32",

"request_date_pst": "2017-01-12 22:57:20 America/Los_Angeles",

"receipt_creation_date_ms": "1484283892000",

"receipt_type": "Production"

}

}

苹果应用内支付(iOS IAP)的流程与常用攻击方式的更多相关文章

  1. 苹果应用内购 ios 开发者根据用户提供的邮件中的订单号查看该订单是否支付成功

    苹果应用内购 ios 开发者根据用户提供的邮件中的订单号查看该订单是否支付成功 这是苹果wwdc2021 推出的新功能 参考官网链接 App Store Server API | Apple Deve ...

  2. 应用内支付(IAP)可加入三方支付

    Windows Phone 放开政策 - 应用内支付(IAP)可加入三方支付   Windows Phone 应用商店在 今年(2013)11月04号 修改了商店政策 允许公司账户的应用使用三方支付S ...

  3. Windows Phone 放开政策 - 应用内支付(IAP)可加入三方支付

    Windows Phone 应用商店在 今年(2013)11月04号 修改了商店政策 允许公司账户的应用使用三方支付SDK. 通过 App certification requirements cha ...

  4. iOS应用内支付(IAP)的那些坑

    本文转载至 http://blog.devtang.com/2013/04/07/tricks-in-iap/ 前言 udacity 中的在线课程 <How to build a startup ...

  5. iOS: 实现苹果的内购

    一.介绍: 在个人开发的app上架到AppStore后,苹果官方允许我们将自己的app在appstore上进行付费使用,也就是所谓的内购.其中,支付方式规定的必须是苹果的支付方式:应用内支付. 二.流 ...

  6. Cocos2dx使用ios内支付IAP具体流程-白白

    今天总结了一下cocos2d-x使用ios内支付iap的具体流程,封装好了调用接口,代码与具体说明在此 http://download.csdn.net/detail/u010229677/81566 ...

  7. IOS应用内支付IAP从零开始详解

    前言 什么是IAP,即in-app-purchase 这几天一直在搞ios的应用内购,查了很多博客,发现几乎没有一篇博客可以完整的概括出所有的点,为了防止大伙多次查阅资料,所以写了这一篇博客,希望大家 ...

  8. IOS IAP APP内支付 Java服务端代码

    IOS IAP APP内支付 Java服务端代码   场景:作为后台需要为app提供服务,在ios中,app内进行支付购买时需要进行二次验证. 基础:可以参考上一篇转载的博文In-App Purcha ...

  9. ios IAP 内购验证

    参考我之前的笔记 苹果内购笔记,在客户端向苹果购买成功之后,我们需要进行二次验证. 二次验证 IOS在沙箱环境下购买成功之后,向苹果进行二次验证,确认用户是否购买成功. 当应用向Apple服务器请求购 ...

随机推荐

  1. apr的使用

    APR(Apache Portable Runtime),即Apache可移植运行库,正如官网所言,APR的使命是创建和维护一套软件库,以便在不同操作系统(Windows.Linux等)底层实现的基础 ...

  2. 【JavaScript 12—应用总结】:弹出登录框

    导读:上篇博客中,做好了个人中心的下拉菜单,这次,将做每个网站都会有的一个登录功能,以此类推,可以做出别的想要的弹出框,如错误提示啦,或者注册. 一.实现分析 首先:和下拉菜单一样,需要通过CSS样式 ...

  3. 九度oj 题目1131:合唱队形

    题目描述: N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1, 2, …, K,他们 ...

  4. fdisk分区自动挂载

    理解/etc/fstab文件配置 首先打开这个文件我们查看下本身内容 vi /etc/fstab   或者   vim /etc/fstab 2 介绍下fstab配置 文件配置每一行属于一个配置,每个 ...

  5. Linux 查看端口占用并杀掉进程

    1. 查看端口号占用情况: netstat -apn|grep 11305 tcp        0      0 10.65.42.27:80              172.22.142.20: ...

  6. BZOJ 2179 FFT快速傅立叶 ——FFT

    [题目分析] 快速傅里叶变换用于高精度乘法. 其实本质就是循环卷积的计算,也就是多项式的乘法. 两次蝴蝶变换. 二进制取反化递归为迭代. 单位根的巧妙取值,是的复杂度成为了nlogn 范德蒙矩阵计算逆 ...

  7. Redis的持久化——RDB

    前面说到redis的三大特性:缓存.分布式内存数据库.持久化,所以今天将为大家介绍redis的两种数据持久化技术RDB和AOF, 先介绍RDB吧. 一.RDB是什么? 1.RDB全称redis dat ...

  8. java面试题之什么是死锁、活锁、饿死和竞态条件?

    死锁:是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用,他们将无法推进下去: 活锁:是指两个线程优先级相同,都礼让不走,就这样一直僵持下去: 饿死:在 ...

  9. PHP实现当前文件夹下所有文件和文件夹的遍历

    <?php function myScandir($dir){ static $flag=''; //设置缩进显示格式 $files = scandir($dir);//读取当前文件夹的文件 $ ...

  10. Codevs 2989 寻找somebody

    时间限制: 2 s 空间限制: 8000 KB 题目等级 : 钻石 Diamond 题目描述 Description 在一个n*m的方阵中 寻找somebody的位置 有可能k不存在输出“bianta ...