Apple ID 第三方授权登录算法深度解析:从 SRP6a 到 Federate Token 的完整链路

一、前言:为什么研究 Apple ID 授权?

最近在做一个支持 "使用 Apple 登录"(Sign in with Apple) 的第三方应用时,发现国内对这块的技术分享非常少。Apple 的授权链路不像微信、QQ 那样有现成 SDK 调用,它走的是一套 类 SRP 零知识证明 + Federated Token 交换 的混合方案,整个流程涉及到密码学协商、签名校验、设备指纹等多个环节。

这篇文章会从协议层面拆解整个授权登录的完整链路,重点分析几个关键节点,并给出我们在逆向过程中总结出来的一些"经验值"。本文仅用于技术研究与安全测试,请勿用于任何非法用途。

二、整体流程概览

一次完整的 Apple ID 授权登录,通常包含以下几个阶段:

┌─────────────┐
│  客户端发起  │  (传入 Apple ID / 手机号)
└──────┬──────┘
       ▼
┌─────────────┐
│ SRP 密钥协商 │  ← get_encrypted_a / get_encrypted_b
└──────┬──────┘
       ▼
┌─────────────┐
│  密码校验通过 │
└──────┬──────┘
       ▼
┌─────────────┐
│ 获取会话凭据 │  ← signin/init / signin/complete
└──────┬──────┘
       ▼
┌─────────────┐
│ Federate交换 │  ← auth_federate → grant_code
└──────┬──────┘
       ▼
┌─────────────┐
│ 换取访问令牌 │  ← token exchange
└─────────────┘

下面我们逐个阶段展开。

三、SRP6a 零知识证明协商

Apple 的登录底层使用的是 SRP-6a 协议(Secure Remote Password, 6a 版本),这是 RFC 5054 中定义的标准协议。客户端不会把密码明文发到服务端,而是通过零知识证明让服务端"相信"你知道密码。

3.1 为什么 Apple 不直接传密码?

  • 避免中间人拿到明文密码
  • 服务端数据库泄露也不会暴露用户密码
  • 即便全程被嗅探,也无法重放

3.2 关键参数协商

客户端首先要调用一个 get_enctypted_a 之类的接口,提交自己的公钥 A(基于随机数 a 生成)。服务端会返回 Bsalt、以及一些协议参数。

我们抓到的一个典型请求伪代码如下:

# 客户端发起 SRP 协商
session_a = random_int(256)        # 私钥 a
A = pow(g, session_a, N)           # 公钥 A = g^a mod N

# 提交给 Apple
post("/get_enctypted_a", json={
    "a": base64(A),
    "account": apple_id,
    # ... 协议版本、设备指纹等
})

这里的 N(大素数)和 g(生成元)是 SRP 协议公开参数,Apple 使用的 1024-bit 安全素数,理论上不可爆破。

3.3 服务端响应处理

正常情况下服务端会返回 Bsalt,但在网络环境差或 IP 被风控时,常见两种异常:

状态码 含义 我们的处理
200 返回 B 和 salt 继续走 proof 校验
503 服务暂不可用(IP 被限流) 切换代理 + 指数退避
400 参数异常 检查 a 是否为 0
401 账号密码错误 直接终止

经验之谈:这里的 503 几乎 100% 是 IP 维度的风控,不是账号维度。所以在做批量场景时,每个并发必须使用不同的高匿代理,且建议池子规模在 50 以上。

四、signin/complete 与会话凭据

SRP 校验通过后,Apple 会下发一个会话级别的凭据(不是最终的 token),这个阶段对应 signin/complete 接口,调用成功后会返回一个 grant_code(也叫 c)。

这是整个链路里最敏感的一步,直接决定了后续能不能拿到联邦令牌。

# signin/complete 伪代码
response = session.post(
    "https://signin.apple.com/api/1.0/signin/complete",
    json={
        "account": apple_id,
        "protocol": "s2k",
        "m1": M1,        # 客户端 proof
        "c": session_id, # 协商阶段拿到的会话id
        "createSession": True
    }
)
grant_code = response.json()["authorizationCode"]

注意几个坑:

  1. IP 并发敏感性极高signin/complete 对同 IP 的并发请求极其敏感,实测 concurrency > 2 就会出现 503。
  2. 必须携带协议版本号:低版本的 protocol 字段会被拒绝。
  3. 客户端 proof M1 算错就直接 401,没有重试机会。

五、auth_federate 与联邦令牌

拿到 grant_code 后,调用 Apple 的 auth_federate 接口,将 Apple 账号的会话凭据转换为第三方应用可用的 OAuth token

# 联邦令牌交换
resp = session.post(
    "https://appleid.apple.com/auth/federate",
    json={
        "authorizationCode": grant_code,
        "clientId": YOUR_CLIENT_ID,
        "redirectUri": YOUR_REDIRECT,
    }
)

federated_token = resp.json()["access_token"]

这个阶段有几个反爬特征

  • 请求必须携带 signx-heliosx-medusa 等自定义头
  • 这几个头的生成涉及 HMAC-SHA256 + 时间戳 + 设备指纹,具体算法各家逆向结果不一样(属于 App 风控的"看门狗")
  • 缺失或错误任何一个,直接 401,不给具体原因

篇幅原因,这里就不展开签名头的具体生成了。感兴趣的可以自己抓包对比几次正常请求的差异,规律其实不难找。

六、passport 子流程:手机绑定与验证码

部分业务场景下,Apple 会要求二次验证(手机验证码),这套逻辑走的是独立的 passport 子域。流程大致是:

send_code  →  加密手机号  →  平台下发短信  →  用户回填  →  verify

加密方式比较有意思,伪代码如下:

# 加密手机号(伪代码)
def encrypt_mobile(phone: str) -> str:
    # XOR with a fixed byte, then prefix with a marker byte
    encoded = bytes([0x2E]) + bytes(b ^ 0x05 for b in phone.encode())
    return base64(encoded)

# 加密验证码(伪代码)
def encrypt_code(code: str) -> str:
    encoded = bytes(b ^ 0x05 for b in code.encode())
    return base64(encoded)

加密常量在不同版本间可能会变化,实测有遇到 0x05 改成 0x07 的情况,做生产化方案时需要做兼容。

七、批量场景下的工程化经验

最后分享几个我们在工程化时踩过的坑:

  1. 代理质量 > 代理数量:与其用 1000 个烂代理,不如用 50 个高质量 SOCKS5 高匿代理。
  2. 指数退避是必须的:502/503/504/429 一律 2s → 4s → 8s 退避,最多 3 次。
  3. 失败账号不要自动重试:Apple 短时间内对同一账号重试会触发风控,让用户手动重置状态比自动重试安全得多。
  4. session 必须绑死代理:不要多个 worker 共享一个 requests.Session,否则代理一掉全军覆没。
  5. 本地调试必须旁路代理:调用本机服务(localhost:3000 的加密服务)时一定要 proxies={'http': '', 'https': ''},否则会被污染。

八、总结

Apple ID 的授权链路从协议设计上是非常优雅的——SRP 零知识证明 + Federate Token 交换,既保护了用户密码,又给了第三方受控的访问能力。但工程化落地时,反爬策略、IP 风控、签名头校验 这三座大山才是真正难点。

本文只展示了整体框架和部分关键节点的脱敏代码,如果你对:

  • 完整的 SRP6a 协商实现
  • sign/x-helios/x-medusa 签名头生成原理
  • 批量场景下的稳定代理调度方案
  • 苹果设备风控对抗

感兴趣,欢迎评论区留言或私信交流,可以分享更多实战细节和踩坑记录。

posted @ 2026-06-29 09:47  小螺软件宝  阅读(1)  评论(0)    收藏  举报