识别设备 - Corvus 系统设计与 DeviceCheck API

Corvus

一直以来,我们的 Radar 系统(对外也叫“反馈助理”)中就时不时出现一些抽象的反馈,近期甚至经常出现直接开骂的反馈,下图节选了一些:

逆天反馈

因此,我们决定编写一个封禁系统,好好惩治一下这些没素质的用户,Corvus 应运而生。“Corvus” 这个名称来自 “乌鸦座”,乌鸦的象征不好,所以用这个作为代号挺合适的。

首要任务 - 识别设备

要搭建封禁系统,首先需要能够识别需要封禁的设备。由于 Apple 一直以来的隐私保护,现在完全没有办法静默地获取到设备的唯一 ID。唯一能获取到的与设备相关的 ID 是 UIDevice 下的 identifierForVendor,但这个 ID 在用户将设备上所有同开发者的 App 全部删除后就会被重置,无法达到封禁的目的。

还好,Apple 专门为我们提供了用于减少欺诈的 DeviceCheck API。此 API 相对简单,可以大致分为两个部分:Device Identification 和 App Attest,但是用处却不小。Device Identification 部分正好可以用于我们的封禁系统。

Apple 服务器可以对每个设备托管两个比特的二进制数据(也就是两个 Bool 值),确实有点小,但是对于封禁系统已经足够了,我们只需要用到一个比特位。对这些数据的访问流程是:本地设备生成短期设备令牌 -> 设备令牌发送到 Darock 服务器 -> Darock 服务器将设备令牌与开发者验证令牌一同发送至 Apple 以读取/修改数据了解更多访问与修改按设备数据

构建服务端 API

我们在服务端构建了三个 API 端点,分别用于封禁、取消封禁以及查询封禁状态。内部实现逻辑其实都是类似的:生成开发者 JWT 令牌,随后提交数据与传入 API 的用户设备令牌。

因为服务端现在已经完全由 Swift 构建,整个流程的代码很简洁,我们使用了 SwiftJWT 库直接创建 JWT 令牌,再用 Alamofire 发送网络请求就可以了。

本地库 - CorvusKit

我们创建了 CorvusKit 以在本地发起封禁查询以及请求。在 App 启动时,CorvusKit 将向服务器查询封禁状态并更新本地的缓存,并会根据缓存状态在 App 启动时自动为 App 附加全局水印。

一旦设备被附加 Corvus 封禁,App 内会出现透明度为40%的全局水印,提示已被附加 Corvus 封禁,此水印在封禁期间将会一直存在。因为抽象的反馈恶心人,所以我们也用恶心的方法反馈给你😋。

App 可以直接调用 CorvusKit 更新封禁状态,因此在什么时候解除封禁也是交给调用方的。Darock App 采用这样的方法:

  1. 在 Apple Watch 上使用 Cepheus 键盘输入(即只能一个个字输入 + 无智能联想 + 奇幻的触摸偏移)下方内容:

    法律之前人人平等,并有权享受法律的平等保护,不受任何歧视。人人有权享受平等保护,以免受违反本宣言的任何歧视行为以及煽动这种歧视的任何行为之害。

  2. 输入完全匹配后,才允许接下来的步骤。
  3. 在 Apple Watch 上使用 Cepheus 键盘输入(同上)对申诉情况的描述。
  4. 在描述不为空时(即这时,你已完成上方内容的抄写,并在描述中输入了一些内容后)显示 200 字与当前输入字数的差值(剩余字数要求)。简单来说,你至少需要完成上方内容的抄写后才会知道还有 200 字字数要求这回事。
  5. 如果一秒内描述文本新增的字数超过 10 个字,则清空描述内容。
  6. 描述文本达到字数要求后,即可提交申诉。

更新本地库 - RadarKitCore

我们同时更新了 RadarKitCore,以在提交反馈时自动发送设备令牌信息。这并不会降低隐私保护,因为设备令牌是临时的。

备用方案 - 内部反馈

RadarKit 在很久以前就已支持隐藏内部的反馈回复,这些回复通过在回复的 Sender 字段值中在开头添加下划线(_)来标记。我们在 App 启动时遍历曾发送过的反馈,如果反馈的内部回复内容有特定字段与值,App 就会立即自动联系 Darock 服务器以封禁设备。

因为 DeviceCheck API 获取到的设备令牌有时效性,并且以前的反馈并没有设备令牌信息,此方法可以追溯以前的反馈并为想要附加封禁时设备令牌已失效的情况提供 Fallback。

更新内部 App - Radar

最后,我们更新了反馈处理 App Radar 以允许对有设备令牌的 App 直接附加封禁。

写在最后

希望大家一辈子都不要在自己的设备上见到 Corvus 封禁的水印。