WWDC Quick Look 💓 By SwiftGGTeam
Secure your apps with App Attest

Secure your apps with App Attest

观看原视频

Highlight

App Attest 利用 Secure Enclave(安全隔区)生成不可导出的硬件绑定密钥,为服务器提供加密证明,确认请求来自运行在真实 Apple 设备上的未篡改 App。iOS 27 新增 launch validation category 和 bundle version 扩展字段,macOS 27 首次支持并引入 ACL Blob OID 验证系统完整性,同时新增的 Fraud Metric 可检测一台设备在过去 30 天内生成过多密钥的异常行为。

核心内容

你做了一个在线考试 App,学生答题后把答案提交到服务器打分。攻击者反编译你的 App,做一个修改版,直接往服务器提交伪造的高分答案。你的服务器收到请求,看起来和正常请求一模一样,根本分辨不出来。

App Attest 就是用来解决这个问题的。

它的核心思路很简单:让设备上的 Secure Enclave 生成一对密钥,私钥永远留在硬件里,公钥的哈希作为 key ID 返回给 App。App 把这个 key ID 发给服务器,服务器下发一个 challenge,App 拿着 challenge 去请求 Apple 生成 attestation(证明)。这个 attestation 包含证书链、设备硬件快照、App 身份信息,服务器验证后就能确认:这个请求确实来自一个未篡改的 App,运行在真实的 Apple 设备上。

01:53)以前防篡改靠越狱检测、设备指纹,和攻击者玩猫鼠游戏。App Attest 把信任根锚定在 Apple 硬件和 Secure Enclave 上,攻击者无法导出私钥,也无法在另一台设备上复用 attestation。

02:15)除了证明设备真实,App Attest 还能暴露 App 是否被修改。它通过 relying party identifier(Team ID + Bundle ID 拼接)标识你的 App。攻击者重新签名后 Team ID 会变,attestation 里就能看出来。

03:03)iOS 27 新增了两个重要信号:launch validation category 告诉你 App 是从 App Store、TestFlight 还是其他渠道启动的;bundle version 让你确认运行的是不是你发布的版本。攻击者升级 Bundle Version 重新签名,这些变化都会暴露在 attestation 里。

04:08)macOS 27 首次支持 App Attest,这对 Mac 端的高价值业务(金融、游戏反作弊)意义重大。Mac 生态比 iOS 开放,用户可以关闭 SIP(System Integrity Protection)或降级安全策略。Apple 在 macOS 的证书链中加入了 ACL Blob OID,记录了生成密钥时设备是否处于 Full Security 模式和 SIP 开启状态。

16:27)Fraud Metric 是这次最有意思的新能力。它回答了一个老问题:攻击者用几百台真机组成设备农场,每台都是真机,单看 attestation 根本拦不住。Fraud Metric 返回一台设备在过去 30 天内生成的唯一 attested key 数量的近似值。正常用户一台设备一个密钥,如果这个指标飙升,说明这台设备在批量生成凭证,或者被当作代理(broker)为其他设备签发 attestation。

详细内容

判断可用性

04:26)App Attest 支持所有 Apple 平台,包括新加入的 macOS 27。但不是所有 App 类型都可用,需要通过 isSupported 判断:

import DeviceCheck

if DCAppAttestService.shared.isSupported {
    // App Attest 可用,正常集成
} else {
    // 标记为风控信号,限制敏感功能
}

关键点:

  • Action 和 SSO App Extension 支持,其他类型 Extension 不支持
  • isSupported == false 本身可以作为 fraud signal 纳入风险评估
  • 如果一台声称是 iPhone 15 的设备频繁返回不支持,可能已被篡改

生成密钥

05:07)App 调用 generateKey() 生成 Secure Enclave 绑定的密钥对:

import DeviceCheck

let keyID = try await DCAppAttestService.shared.generateKey()
// 把 keyID 存入 Keychain

关键点:

  • 私钥存储在 Secure Enclave,无法导出
  • 每个用户生成一个密钥,或每台设备一个密钥,不要跨用户共享
  • 密钥在 App 更新后仍然有效,但重装 App 或恢复设备(包括 iCloud 备份恢复)会失效
  • 密钥不跨设备同步

请求 Attestation

06:32)密钥生成后,App 向服务器请求 challenge,然后调用 attestation API:

import DeviceCheck

let keyId: String = fetchKeyIdFromKeychain()
let clientDataHash: Data = sha256(serverChallenge)

let attestation = try await DCAppAttestService.shared.attestKey(
    keyId: keyId,
    clientDataHash: clientDataHash
)
// 把 attestation 发给服务器验证

关键点:

  • 服务器必须控制 attestation 的发起,控制请求频率
  • 失败时实现指数退避(exponential back-off),不要硬编码重试逻辑
  • 在后台任务中执行,不要阻塞用户流程
  • 验证必须由服务器完成,不要信任客户端的验证结果

Attestation 对象包含三部分:format(固定字符串标识 Apple 匿名证明)、attestation statement(证书链和 receipt)、authenticator data(App 和证明信息)。

证书链证明密钥在真实 Apple 硬件上生成,leaf certificate 包含 nonce、key ID、relying party identifier。macOS 27 还包含 ACL Blob OID,记录 Full Security 模式和 SIP 状态。

10:28)iOS 27 的 authenticator data 末尾新增 extensions 结构,包含两个字段:

  • launch validation category:App Store、TestFlight 或其他
  • bundle version:当前运行的 App 版本

服务器应监控这些字段的异常值,纳入风险评估。

生成 Assertion 保护通信

12:33)Attestation 验证通过后,App 可以用同一个密钥生成 assertion,保护后续请求:

import DeviceCheck

let keyId: String = fetchKeyIdFromKeychain()
let clientDataHash: Data = sha256(serverChallenge)

let assertion = try await DCAppAttestService.shared.generateAssertion(
    keyId: keyId,
    clientDataHash: clientDataHash
)
// 把 assertion 嵌入请求 payload 发给服务器

关键点:

  • Assertion 在设备本地生成,不经过 Apple 服务器,可以按需实时生成
  • 涉及加密运算,有 CPU 开销,避免高频批量生成
  • 服务器必须验证 assertion 中的 counter 严格递增,防止重放攻击
  • 如果 counter 不变或下降,说明可能是被篡改的 App 副本

常见陷阱

15:02)几个容易踩的坑:

用户重新安装 App 或恢复设备会导致 key rotation,不要直接拒绝新密钥。保留历史密钥记录,结合 Fraud Metric 判断是否为异常行为。

验证失败时不要直接阻断用户。先降级功能(限制提现额度、隐藏敏感数据),在加强监控的同时允许有限访问。

Fraud Metric

16:35)Fraud Metric 检测 compromised 设备作为 broker 为其他设备签发 attestation 的攻击模式。服务器用 attestation 中的 receipt 向 Apple 的 App Attest data server 发起 POST 请求,获取 fraud metric。

返回的 receipt 包含签名、证书链和 payload,其中 risk metric 字段就是 fraud metric 计数。这个计数是近似值,表示过去 30 天内该设备上生成的唯一 attested key 数量。

receipt 有刷新窗口,由 not beforeexpiration time 字段控制。正常用户的 App 重装或设备恢复也会贡献到 fraud metric,所以不要直接用它阻断用户,而是作为调查信号,监控基线,识别异常峰值。

核心启发

给金融 App 加上交易签名

做什么:在转账、支付等关键操作前,用 App Attest assertion 对交易 payload 签名,服务器验证后才执行。 为什么值得做:即使攻击者拿到了用户密码,也无法用篡改的 App 发起有效交易请求。 怎么开始:在交易提交前调用 generateAssertion,把 assertion 和交易数据一起发给服务器,后端验证 assertion 的签名和 counter。

给游戏加上排行榜防作弊

做什么:玩家提交分数时附带 assertion,服务器验证 App 未被修改后才计入排行榜。 为什么值得做:防止攻击者注入作弊菜单后提交虚假高分。 怎么开始:在分数提交接口中要求 assertion,同时监控 launch validation category 和 bundle version,异常值直接拒绝。

用 Fraud Metric 识别设备农场

做什么:把 Fraud Metric 接入风控引擎,标记异常设备。 为什么值得做:设备农场里的每台设备都是真机,传统设备指纹拦不住,但 Fraud Metric 能暴露一台设备批量生成密钥的行为。 怎么开始:服务器定期刷新 receipt 获取 fraud metric,设置阈值告警,结合其他风控特征综合判断。

给 macOS App 加上完整性校验

做什么:macOS 27 首次支持 App Attest,利用 ACL Blob OID 验证设备是否开启了 Full Security 和 SIP。 为什么值得做:Mac 端的高价值业务(如企业软件、付费工具)以前缺乏可靠的防篡改手段。 怎么开始:解析 attestation 证书链中的 ACL Blob OID,检查 Full Security 和 SIP 状态,关闭 SIP 的设备标记为高风险。

用 isSupported 做第一道风控门槛

做什么:把 isSupported 的返回值纳入用户风险评估。 为什么值得做:越狱设备或篡改环境可能让 App Attest 不可用,这个信号本身就是异常指标。 怎么开始:记录每个用户的 isSupported 响应历史,突然出现大量 false 的设备重点监控。

关联 Session

  • 101 Keynote — WWDC26 开场,概述 Apple 平台安全新方向
  • 347 Security agentic — 安全领域的 Agentic 应用,与 App Attest 的风控思路互补
  • 379 Trust Insights — 信任洞察相关 session,涉及安全评估和风险控制
  • 205 App Store — App Store 分发和验证,与 launch validation category 相关
  • 262 Swift — Swift 语言新特性,可能涉及安全相关的语言层面改进

评论

GitHub Issues · utterances