唐巧的博客

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

字数统计: 2.4k阅读时长: 8 min
2013/04/07

前言

udacity 中的在线课程 《How to build a startup》 中提到,所谓创业,就是尝试寻找新的赢利模式。正因为这是一种尝试,所以不可避免地需要调整产品方向,寻找市场中还未被发现的用户需求,给用户创造价值,进而获得收入。最近很火的 精益创业 的观点,则是强调将这种尝试成本降到最小,使得自己可以根据市场反馈迅速调整产品。

我们在今年春节后上线了新的在线智能题库:猿题库。这应该是我们在互联网教育这个创业领域尝试的第二个方向。

猿题库现在推出了公务员考试行测和申论 2 个产品,均包括 web, iOS 和 Android 三个平台。这次我们尝试做一个收费的产品,所以在 iOS 端集成了应用内支付(IAP)功能。在开发过程中和上线后,我们遇到了 IAP 中的一些坑,在此分享给各位。

IAP 审核相关的坑

IAP 开发的详细步骤我写在 另一篇博客 中了。在此主要介绍审核时遇到的问题。

IAP 类型错误

由于我们是按月付费的产品,所以在设置 IAP 类型时,我没有经验,只是简单设置成了可重复消费 (Consumable) 的 IAP 项目。但是我不知道,苹果对于这种按时间收费的产品,应该使用不可更新的定阅(Non-Renewing Subscription)类型。这个类型设置错误造成了我们 app 的一次审核被拒。

IAP 验证逻辑

由于苹果在 iOS5.0 以下有 IAP 的 bug,使得攻击者可以伪造支付成功的凭证。而 iOS6.0 的系统在越狱后同样可以伪造凭证,所以我们对于应用内支付,增加了服务器端的验证。
服务器端会将支付凭证发给苹果的服务器进行二次验证,以保证凭证是真实有效的。

在我们公司的测试服务器中,我们会连接苹果的测试服务器( https://sandbox.itunes.apple.com/verifyReceipt )验证。

在我们部署在线上的正式服务器中,我们会连接苹果的正式服务器( https://buy.itunes.apple.com/verifyReceipt )验证。

我们提交给苹果审核的是正式版,我们以为苹果审核时,我们应该连接苹果的线上验证服务器来验证购买凭证。结果我理解错了,苹果在审核 App 时,只会在 sandbox 环境购买,其产生的购买凭证,也只能连接苹果的测试验证服务器。但是审核的 app 又是连接的我们的线上服务器。所以我们这边的服务器无法验证通过 IAP 购买,造成我们 app 的又一次审核被拒。

解决方法是判断苹果正式验证服务器的返回 code,如果是 21007,则再一次连接测试服务器进行验证即可。苹果的 这一篇文档 上有对返回的 code 的详细说明。

IAP 上线后的遇到的情况

我们在服务器端增加了验证 IAP 是否有效的逻辑。在产品上线后,如我们所料,我们收到了大量的欺骗性购买,这些都被我们的服务器识别出来了,但是我们也遇到了以下这次没有想到的情况:

1、由于国内越狱用户的比例比较大 (2012 年底国内越狱比例是 42%), 所以虽然我们服务器会验证购买凭证,但是每天有超过 50% 以上的凭证都是伪造的。同时由于苹果的验证服务器在美国,凭证验证请求响应的时间比较慢,大量的伪造凭证发给苹果服务器,不知道会不会被苹果认为我们是在恶意进行 DDOS。至少我们发现有些时候,验证请求会超时。

2、由于国内有许多小白用户,他们的手机从购买时就被渠道商帮忙越狱过了并且安装了 IAP free 插件。所以对于这类用户,他们即使想付费购买,由于系统原有的 IAP 支付功能已经被破坏,所以他们是无法正常付费的。麻烦的是,他们会以为这是我们的 app 的问题,转而给我们的客服打电话投诉。这让我们非常郁闷。

3、苹果的验证服务器有时候会出问题,我们发现本来约定好返回的 JSON 数据在有几次返回的居然是一个 XML 格式的文件。造成我们将正常的付费 IAP 凭证验证失败。所以,在服务器记录下所有的验证凭证非常有必要,一来可以防止黑客多次提交同一个成功凭证的重放攻击,二来在需要时可以手工进行再验证。

越狱手机可能被黑客窃取购买凭证!!

我们发现有一部分用户反馈说已经收到苹果的扣费账单,但是我们从服务器的验证记录看,他上传的凭证却是虚假的。由于这些用户不太多,我们一开始以为是用户在恶意欺骗我们,后来我们让他将苹果的付费账单邮件转发给我们,以及将 itunes 的购买记录截图转发给我们,随着讨论的深入,我们越来越怀疑这里面有一个黑色的产业链。越狱手机的正常购买凭证可能被黑客的恶意程序截获,具体的攻击方式我们讨论了一下,其实就是被 中间人攻击,详细的过程如下:

  1. 越狱手机的在被破解后,可能从一些破解渠道安装了黑客的恶意程序。
  2. 黑客将越狱手机所有 https 请求都经过他的中间服务器。
  3. 当有支付请求时,黑客先将请求发给苹果服务器,待苹果将成功的凭证返回后,黑客将这个凭证替换成假的凭证,完全支付凭证的偷取。

或许有人会问,这个凭证拿来有什么用呢 ? 很简单 ,因为苹果为了保护用户的隐私,支付凭证中并不包含任何用户的 apple id 信息,所以我们的 app 和服务器无法知道这个凭证是谁买的,而只能知道这个凭证是真的还是假的。于是黑客就可以用这个凭证,在另外的账号中通知我们完成了购买,而发来的验证凭证又是真实的,所以我们的服务器就会误认为是黑客的账号完成了购买,继而把会员期算在黑客的账号上。

再举一个简单的例子,你拿 500 块钱买了顺风优选的 500 元购物券,由于这个购物券是不记名的,所以顺风优选无法知道是谁买的。如果这个购物券在发放过程中被人掉包,那么偷购物券的人就可以拿这个偷来的真购物券来购物,而顺风优选的卡因为是不记名的,所以也无法查证这件事情。在这个例子中,购物券的不记名和苹果的支付凭证无账号信息是同一个道理。

鉴于以上情况,考虑到越狱手机不但不能成功支付,还会有安全问题,所以我们在新版中取消了越狱手机中的 IAP 支付功能。

所以,请大家还是不要越狱自己的手机,iPhone 手机越狱后风险相当大。实在不值得为了免费玩几个游戏就丢掉安全性。

后记

中间人攻击的演示

iOS 独立开发者 王轲 _IndieBros 在他的博客文章 《使用 mitmproxy 获取 iTunes 11 的 Raw HTTPs Response》 中演示了如何使用中间人攻击来修改 Game Center 游戏数据。王轲还把我的例子白话翻译了一下(可见我还是说得太绕了,囧):

坏人在购买过程中插了一腿,换走了用户的无记名发票(购物小票形象些),然后手持无记名小票伪装成真实顾客或者转手出售获利。

关于越狱与盗版

不少细心的同学评论纠正我,指出越狱并不等同于使用盗版。确实,如果说严格的定义,越狱只是让 iPhone 获得 root 权限,进而可以做任何事情。如果越狱的同学在越狱后不安装 IAP free 插件,不使用 app sync 插件,不使用任何国内的和非 bigboss 的 cydia 源,不使用任何盗版软件,所有应用都是从 app store 官方网站上下载的话,被黑客攻击的可能性会降低一些。

即使这样,由于手机已经被 root 了,苹果的沙盒安全机制失效,所以风险还是很大的。

关于越狱用户的比例

有同学提出我文章中写的越狱手机比例太高了,想询问数据来源。这个比例主要来自我们自己的 app 的统计信息,以及结合国内的统计工具友盟的 越狱手机比例统计,去年底国内的越狱比例是 42%。

CATALOG
  1. 1. 前言
  2. 2. IAP 审核相关的坑
    1. 2.1. IAP 类型错误
    2. 2.2. IAP 验证逻辑
  3. 3. IAP 上线后的遇到的情况
  4. 4. 越狱手机可能被黑客窃取购买凭证!!
  5. 5. 后记
    1. 5.1. 中间人攻击的演示
    2. 5.2. 关于越狱与盗版
    3. 5.3. 关于越狱用户的比例