Surge 2.0 是如何实现在 iOS 上反盗版的

Surge 从上架至今一直遇到了各种带有中国特色的盗版问题,其中最严重的是通过直接分享 Apple ID 账号进行下载的方法,甚至已建起了“官网”,明码标价式的销售,非常可恶。在 Google 上搜了很久,似乎在中国之外并没有人在讨论这种盗版方式,无奈之内自己研究对策。

Apple 非常注重用户的隐私,没有任何可以拿到用户关键隐私数据的 API,或者是需要授权(如通讯录)。我非常赞同 Apple 在这方面的隐私考虑,但这确实给反盗版工作带来了很大的困难。但在激活过程中,Surge 同样非常尊重用户隐私,没有任何用户的隐私数据会被收集。

(其实 iOS 9 中各种 API 限制都已经的非常完备了,想获取也拿不到……)

1. 如何鉴别单次购买行为 (同一 Apple ID)

我们的目的是限制单 Apple ID 大量的用于不同设备上的激活,所以首先需要鉴别某次激活请求是否和另外的请求来源自同一购买行为:

有做过 In App Purchase 的工程师应该知道 receipt 的存在,这是进行 iAP 验证的唯一有效渠道,因为它可由服务器端向 Apple 服务器请求确认,且具有唯一的 ID (transaction_id) 可以防止重放攻击。

Receipt 本身也记录着应用的购买信息,样例如下:

“receipt”: {
“receipt_type”: “Production”,
“adam_id”: xxxx,
“app_item_id”: xxxxxx,
“bundle_id”: “me.yach.surge-ios”,
“application_version”: “629”,
“download_id”: xxxx,
“version_external_identifier”: xxxxxxx,
“receipt_creation_date”: “2016–06–30 04:18:37 Etc/GMT”,
“receipt_creation_date_ms”: “1467260317000”,
“receipt_creation_date_pst”: “2016–06–29 21:18:37 America/Los_Angeles”,
“request_date”: “2016–06–30 04:18:39 Etc/GMT”,
“request_date_ms”: “1467260319862”,
“request_date_pst”: “2016–06–29 21:18:39 America/Los_Angeles”,
“original_purchase_date”: “2015–10–26 03:13:07 Etc/GMT”,
“original_purchase_date_ms”: “1445829187000”,
“original_purchase_date_pst”: “2015–10–25 20:13:07 America/Los_Angeles”,
“original_application_version”: “290”,
“in_app”: []
}

然而,在针对应用的购买信息中,却少了唯一性的 ID,所以没有办法鉴别该收据是否代表着是同一次购买行为。

但是,仔细观察 receipt,有一个字段其实可以等同于唯一性 ID:original_purchase_date_ms,购买的时间戳。所以,利用该字段,即可按照单次购买行为进行激活限制。

2. 策略

为了在尽可能的不影响正常用户的使用的前提下,打击大规模的盗版分享行为,设计了以下策略

  1. 激活于 2016 年 7 月 3 日开始,预留了时间给我在 2.0 版本于 App Store 发布后,提前进行测试,确保各项流程顺利。
  2. 进入待激活状态后,用户可以推迟激活,最长 14 天,避免因为要求激活而导致直接无法使用,用户可以在方便的时间点再进行激活。
  3. 一旦设备进行激活后,除非进行 Restore 刷机,否则不再需要进行激活。
  4. 单次购买行为,在最近半年内,最多可以激活 10 台设备。(即从当前时间往前 6 个月内,若已成功激活的设备数量超过 10 台,则拒绝激活新设备。)
  5. 可以通过邮件进行单独激活,作为意外情况的备用方案。

至于为什么是 10 台,因为对于绝大多数用户来说,都不会触发到这个限制。另外,App Store 的 EULA 已经限制了,单 Apple ID 仅能在由自己拥有或控制的,最多 10 个设备上所使用。

http://www.apple.com/legal/internet-services/itunes/appstore/jm/terms.html
当然有认真的朋友可能会指出苹果是允许 90 天后变更设备的,或者其他 balabala 的细节。在此说明一下,我并非不允许超过 10 设备的使用,只要确实是自用的设备的话,请按照错误提示发邮件进行单独激活,此乃为了打击盗版的无奈之举,如若导致正版用户的不便请见谅。

3. 具体实现

由于 Receipt 可被 Apple 的服务器所验证,所以我们可以构造出以下信任链:

iDevice 硬件验证 → iOS 系统完整性 → Surge 二进制安全 → Surge 只接受来自特定服务器的激活确认 → 服务器向 Apple 确认收据是否真实 → Apple 服务器验证

在此信任链下,激活流程理论上不可破解。越狱设备会破坏信任链,变成一个猫捉老鼠的防御,目前 Surge 并未太关注越狱设备上反盗版。

另外,可能的隐患是,两个不同的用户在完全一致的时间上购买了 Surge,导致 original_purchase_date_ms 相同。有几点因素可以来弥补这项缺陷:

  • Surge 的购买量很低,在精确到秒的同一时间购买的概率非常低。
  • 大部分用户只有 1-2 台设备,即使出现了这种罕见的碰撞,也不会触发激活限制,对大部分用户来说并不影响使用。
  • 有通过邮件进行人工激活的补救渠道。

最后,衷心希望开发者以后能在反盗版这样的事情上少花点精力。