关于

了解 DUSTO 的现在以及未来。

初衷

DUSTO 诞生的初衷是为了维护 iOS 开发者的利益。

为什么使用 DUSTO ?

DUSTO 可以从根源上阻止基于共享帐号的盗版行为。

作为 iOS 开发者,你不需要再到淘宝、微店、拼多多、闲鱼等平台申诉(不仅浪费时间,而且大部分情况下都没有效果)。

注册

DUSTO 通过「邀请制」完成注册。

如果你是一名饱受共享帐号盗版困扰的 iOS 开发者,欢迎通过 Telegram 与 @z3k3c1 联系。

隐私

DUSTO 不窥探、不分析用户数据。

收费 / 捐赠

DUSTO 不向开发者收取任何费用,也不接受任何形式的捐赠。

工作原理

了解 DUSTO 是如何工作的。

基本原理

  • 关联「购买」与「用户」,统计某一「购买」被不同「用户」使用的次数。
  • 通过统计到的使用次数来识别和封禁「购买」。

如何识别「购买」?

StoreKit 返回的购买回执中包含一个时间戳,它对应着此次购买的付款时间。因为多位用户的付款时间很难在秒级别出现碰撞,所以这个时间戳在一定程度上可以作为此次购买的唯一标识。

数据示例:

1584763266000

DUSTO 将此类数据称为「唯一购买标识」。

如何识别「用户」?

因为 Apple 的隐私政策,应用开发者无法获取用户的 Apple ID,但是通过 CloudKit 可以获取 Apple ID 的 Hash 值。这个 Hash 值可以直接作为用户的唯一标识。

数据示例:

_85dec2bc70552fa19c1ca0c60e88af85

DUSTO 将此类数据称为「唯一用户标识」。

接入指南

了解如何在 iOS 应用中接入 DUSTO。

基本流程

  1. 检测「购买」:
    • 检测到购买已激活,则在应用内获取「唯一购买标识」与「唯一用户标识」,并通过 DUSTO 所提供的 HTTP API 将二者发送至 DUSTO。
    • DUSTO 获取到以上数据后,会检测「购买」的合法性,并响应结果。
  2. 自定义「处理逻辑」:
    • 应用内根据以上的返回结果来定义针对检测结果的处理逻辑。
  3. 为用户提供获取「唯一购买标识」的途径。

下面分别对这几个步骤进行介绍。

检测「购买」

DUSTO 提供了可以简化接入流程的 SDK

应用开发者可以阅读其中的文档、示例代码、以及下面的文档,来理解 DUSTO 的接入流程。

注意:SDK 中不包含获取「唯一购买标识」和「唯一用户标识」的相关代码。开发者需要根据自己的需求并结合下面的文档来获取。

提示:如果想要自己实现接入相关的代码,可以跳转到「附录」中查看详细接入流程。

获取「唯一购买标识」

通过 StoreKit 获取购买回执,解析其中包含的时间戳 original_purchase_date_ms

回执示例(有意去除了不相关信息):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  # ...
  <key>receipt</key>
  <dict>
    # ...
    <key>in_app</key>
    <array>
      <dict>
        # ...
        <key>original_purchase_date_ms</key>
        <string>1599313352000</string>       # 「免费 + 内购」销售模式使用该时间戳
        # ...
      </dict>
      # ...
    </array>

    # ...
    <key>original_purchase_date_ms</key>
    <string>1596182470000</string>           # 「付费下载」销售模式使用该时间戳
    # ...
  </dict>
</dict>
</plist>

更完整的示例,请查看上文提到的示例项目。

获取「唯一用户标识」

通过 CloudKit 获取 Apple ID 的 Hash 值。

示例代码:

CKContainer(identifier: "iCloud.top.dusto.xxx").fetchUserRecordID

更完整的示例,请查看上文提到的示例项目。

自定义「处理逻辑」的一个示例

下面以一个采用「免费 + 内购」销售模式的应用为例,来展示一个可能的处理逻辑。

以下为伪代码:

if (内购已激活) {

    获取「唯一购买标识」
    获取「唯一用户标识」
    向 DUSTO HTTP API 发送请求,检测以上两个标识

    if (请求失败) {
        重试。多次失败后,则不作处理(避免 DUSTO 故障影响应用)
    } else if (请求成功,检测结果为非法购买){
        关闭内购,提示用户:“你可能是盗版受害者。如有疑问,可以联系我们,发起申诉。”
    } else { // 请求成功,检测结果为合法购买
        不作处理
    }

}

提供「唯一购买标识」的获取途径

由于 DUSTO 可能误判,因此需要为用户提供获取「唯一购买标识」的途径。

一个可能的实践:连击应用版本号 5 次后,应用自动将「唯一购买标识」复制到剪贴板。

在发生误判时,用户向开发者提供「唯一购买标识」,开发者在 DUSTO 中查询后,根据结果进行处理。

附录

HTTP API 的基础格式

POST /api/validate_purchase
Content-Type: application/json
Accept: application/json
Authorization: DUSTO {ACCESS_KEY}:{HMAC_SHA256_SIGNATURE}
X-Auth-Timestamp: 1616082750

{
  "purchase_id": "2584763269001",
  "user_id": "_85dec2bc70552fa19c1ca0c60e88af86"
}

解释:

  1. 使用 POST 方法请求 /api/validate_purchase
  2. HTTP API 使用 JSON 格式通讯,Content-TypeAccept 两个 HTTP 头用来保证使用了 JSON 格式进行通讯。
  3. Authorization HTTP 头中包含签名相关信息。其中,{ACCESS_KEY} 可以从 Integration 面板中获取。{HMAC_SHA256_SIGNATURE} 是将 Request Method、Request PATH、序列化后的 Request Body 以及 X-Auth-Timestamp 头用 + 按顺序拼接后,使用 HMAC-SHA256 计算所得的签名(下一节会详细介绍)。
  4. X-Auth-Timestamp HTTP 头中包含发起请求时的 UTC 时间所对应的秒级 UNIX 时间戳。这个时间戳的可接受误差范围是 60 秒。
  5. 请求体格式为 JSON,其中 purchase_id 对应「唯一购买标识」,user_id 对应「唯一用户标识」。

HTTP API 的签名计算方法

以上述请求为例:

  • Request Method 为 POST
  • Request Path 为 /api/validate_purchase
  • 序列化后的 Request Body 为 {"purchase_id":"2584763269001","user_id":"_85dec2bc70552fa19c1ca0c60e88af86"}

序列化的方式:将 JSON 中的数据按照 key 的字母顺序排序,并去除所有空白字符。

  • X-Auth-Timestamp 头中包含的时间戳为 1616082750

+ 将上述内容按顺序拼接后得到需要签名的字符串(下文中将此数据称为 MESSAGE):

POST+/api/validate_purchase+{"purchase_id":"2584763269001","user_id":"_85dec2bc70552fa19c1ca0c60e88af86"}+1616082750

从 Integration 面板中获取与 ACCESS KEY 对应的 ACCESS SECRET。这里假设:

  • ACCESS KEY 为 bFX4HgXiJHRERhdX
  • ACCESS SECRET 为 topQUN7wnP-9qPnX4sJ7RsOSEOyXB48h

使用 ACESSS SECRET,以 HMAC-SHA256 算法对 MESSAGE 进行签名,得到:

ba2d2015d2cb08948c7cd718121cd56c97863b67ebe4d2361f43412890c680b4

再用 BASE64 进行一次编码,就得到了最终的签名:

YmEyZDIwMTVkMmNiMDg5NDhjN2NkNzE4MTIxY2Q1NmM5Nzg2M2I2N2ViZTRkMjM2MWY0MzQxMjg5MGM2ODBiNA==

DUSTO 使用了 danharper/hmac-examples 提供的 HMAC-SHA256 计算方法。应用开发者自行实现签名时,需要保证与其兼容。

HTTP API 的请求示例

POST /api/validate_purchase
Content-Type: application/json
Accept: application/json
Authorization: DUSTO hXJLs_2UzSRQFgqT:ODlkY2E5OWY3ZmU1MGUyYzBiNjg1NmU5MjExM2Q5MTNkOGFiYzBlNTliZmU5YmRhN2QyZTY5ZWVjNDg2MmY2NQ==
X-Auth-Timestamp: 1616082750

{
  "purchase_id": "2584763269001",
  "user_id": "_85dec2bc70552fa19c1ca0c60e88af86"
}

HTTP API 的响应示例

判定为有效「购买」:

{
  "data": {
    "status": "valid"
  }
}

判定为无效(恶意)「购买」:

{
  "data": {
    "status": "invalid"
  }
}

使用指南

了解如何使用 DUSTO。

全局开关

DUSTO 提供了应用级别的全局开关。

在关闭检测后,DUSTO 会将所有的检测请求判定为合法。

开发者可以在任意时刻关闭 DUSTO 检测,不会给应用带来任何影响。

该功能在应用已经上架,但又不想继续使用 DUSTO 所提供的服务时非常有用。

用户申诉

在面对用户申诉时,应用开发者可以通过 DUSTO 的面板查询「用户」与「购买」的详情,根据情况解除封禁或者不予理睬。

合理的分享次数

默认情况下,DUSTO 允许某一「购买」被 5 个「用户」使用。这是我们通过以往的观察所得到一个合理值。

在我们的数据中:

  • 99% 的「购买」只会被一个「用户」使用。
  • 0.9% 的「购买」会被合理地分享,但都不超过 5 次。
  • 0.1% 的购买会被恶意分享。

解除封禁

DUSTO 提供了解除封禁的功能,因为:

  • 回执中的付款时间存在碰撞的可能性,如果用户运气很差,有可能发生误判。
  • 合理范围内的分享应该是被允许的,如果用户使用了多个属于自己的 iCloud 账户,有可能发生误判。

发生误判时,可以通过提高「用户」对应「购买」的最大使用次数来解除封禁。

FAQ

常见问题汇总。

为什么接入 DUSTO 后,它没有按照预期工作?

DUSTO 的正常工作需要两个前提:

  1. 应用可以联网。否则,应用无法与 DUSTO 服务端通讯。
  2. 用户已经登录 iCloud。否则,无法获取「唯一用户标识」。

如果盗版用户有意不登录 iCloud、关闭联网权限,那么 DUSTO 就无法工作了。

不过,先不用沮丧。由于分散的个体难以达成共识,总会有人联网、总会有人登录 iCloud,只要这样做的用户数量足够多,总是可以检测到恶意「购买」的。

DUSTO 可以支持我的全球业务吗?

DUSTO 使用 Cloudflare 进行全球加速。

在中国以外的地区,不管是控制台,还是 HTTP API,都有着不错的响应速度。

在中国,虽然响应速度会受到特殊网络环境的影响,但是 HTTP API 的连通性是可以保证的,所以可以放心地集成到应用中。在访问控制台时,为了保证不错的响应速度,视不同地区,可能需要科学上网。

综上所述,DUSTO 是可以支持全球业务的。

DUSTO 可以保证用户数据的安全吗?

接入 DUSTO 后,只有上文提到的两个标识会被发送到 DUSTO。DUSTO 只使用这两个标识来判断购买和用户的唯一性,不作他用。

即使在最坏的情况(DUSTO 被爆库)中,这两个标识完全泄漏,也不会对用户造成任何影响:

  • 唯一购买标识:本质上只是一个时间戳,不足以用来与 Apple ID 进行关联。
  • 唯一用户标识:本质上是 Apple ID 的 Hash 值,仅在访问 Cloud Database 时有用。不过,由于 Cloud Database 的通信过程无法从外部干预,即使该 Hash 值泄漏,也难以被利用。

DUSTO 可以保证系统的稳定运行吗?

DUSTO 采用了滚动升级的部署方式,即使在应用更新时也可以保证系统的可用性。

另外,DUSTO 还配备了完善的硬件监控和网络监控,可以及时发现影响可用性的潜在问题。

DUSTO 为什么使用这么繁琐的 HMAC-SHA256 签名方式呢?

DUSTO 一定动了某些人的蛋糕。有些人不会觉得自己错,甚至可能会穷凶极恶地进行反击。DUSTO 对此做好了准备:

  1. HMAC-SHA256 签名在数据传输过程中不会传输 ACCESS SECRET,并且可以保证数据的一致性。这可以有效防御请求伪造。
  2. 签名时加入的 X-Auth-Timestamp 时间因子限制了请求的有效期。这可以有效防御重放攻击和 DDoS 攻击。

如果盗版用户都使用分享帐号来登录 iCloud 呢?

DUSTO 的工作机制确实无法防御这种使用方式。

但是,使用共享账号的用户,并不会使用共享账号来登录 iCloud —— 这是使用共享账号盗版的常识。

鸣谢

感谢向世界分享智慧的人们。

在构建 DUSTO 的过程中,我们参考了:

DUSTO 的诞生离不开以上开发者们的分享。

EOF