为什么DIY AirTag离不开Anisette Server?NinjiaTag苹果iCloud认证机制与SRP免密登录深度剖析
【免费下载链接】NinjiaTag-backend 项目地址: https://gitcode.com/gh_mirrors/ni/NinjiaTag-backend
NinjiaTag 是一个面向 DIY AirTag(兼容苹果 Find My 网络)的服务端后端项目:它通过 Anisette Server 通过苹果的设备验证,用 SRP 免密登录协议认证你的 Apple ID,自动拉取定位标签的轨迹数据并存入自己的数据库,实现任意时间段轨迹查询。这篇文章拆解它背后的 iCloud 认证机制。
📍 什么是 DIY AirTag?它是怎么被定位的?
先说结论:DIY AirTag 本身没有 GPS,它的工作方式是:
- 蓝牙标签周期性广播一个"加密身份"(密钥,实为加密后的 MAC 地址);
- 路人 iPhone 收到广播后,转发给 Find My 网络;
- 苹果服务器匹配并加密位置信息,暂存在你的 Apple ID 名下(最多约 7 天);
- NinjiaTag 后台通过 iCloud 认证接口登录你的 Apple ID,定期把这份数据拉取下来、解密,并永久存入本地 SQLite 数据库——这正是它能"任意时间段回溯轨迹"的关键。
相比主流产品"最多记录 7 天",NinjiaTag 支持不限时长存储、任意时间段查询、热点热图和 GPX 导出。
硬件本身只是一块极简的 nRF5x 或 ST17H66 蓝牙模块(下图是一块标注了 LDO 稳压器的低成本模块,用 USB 供电即可烧录):
完整的硬件刷机与使用说明见 usr_guide/2032_TAG.md 与 flash_guide/ST17H66.md。
🔐 Anisette Server:为什么每次请求苹果都要"设备护照"?
部署 NinjiaTag 时最让人困惑的一步是:为什么连一个苹果接口,还要先跑一个名为 anisette 的 Docker 容器?
答案是:苹果的认证接口不只校验 Apple ID 和密码,每个请求还必须携带一组 X-Apple-I-MD 请求头,即 Anisette 令牌——它相当于证明"我是一台真 Mac"的设备护照:
- 令牌由 Mac 硬件内的 ADI 数据配合 provisioning 流程生成,官方路径依赖实体 Mac;
- 而你手上往往只有一台 Linux 服务器,开源的 Anisette Server(
dadoum/anisette-v3-server镜像)就是在服务器上模拟这一 provisioning 过程,随请求返回有效的 Anisette 令牌。
在代码里,这段逻辑位于 pypush_gsa_icloud.py 的 generate_anisette_headers():它优先向本地 6969 端口的 Anisette 服务器索取令牌,只有装了 pyprovision 且持有 Mac 硬件时才走本地生成。所以——不部署 Mac 的 Linux 服务器方案,完全依赖 Anisette Server,这就是"离不开"的含义。
部署只需两条 Docker 命令:
docker network create mh-network
docker run -d --restart always --name anisette -p 6969:6969 \
--volume anisette-v3_data:/home/Alcoholic/.config/anisette-v3/ \
--network mh-network dadoum/anisette-v3-server
💡 国内网络拉取镜像失败时,需按 README.md 配置 Docker 镜像加速源并重启 docker。
🗝️ SRP 免密登录:iCloud 密码如何"从不上网"?
你很快会注意到:NinjiaTag 拉取位置时只需输入一次 Apple ID 和密码,之后就能无人值守运行。原因在于认证采用了 SRP(Secure Remote Password,安全远程口令) 协议——一种"我知道密码,但绝不把密码发出去"的登录方式:
- 服务端不存明文密码,只存基于盐值派生的校验量;
- 客户端与服务端通过数学"挑战—应答"各自推导出同一个会话密钥,双方都确认对方"真的知道密码",登录即完成;
- 全程密码本体与哈希都不经过网络,中间人也无法重放冒领。
pypush_gsa_icloud.py 中 gsa_authenticate 函数完整实现了这个流程,配置 srp.rfc5054_enable() 以对齐苹果的实现:
┌──────────────┐ ① init:发送随机数 A(不含任何密码信息) ┌──────────────┐
│ NinjiaTag │ ───────────────────────────────────────▶ │ Apple GSA │
│ 后端 │ ◀─────────────────────────────────────── │ 服务器 │
└──────────────┘ ② challenge:返回盐值 s、迭代次数 i、挑战数 B └──────────────┘
┌──────────────┐ ③ complete:发送证明 M1(由密码在本地推导) ┌──────────────┐
│ 后端 │ ───────────────────────────────────────▶ │ Apple │
│ │ ◀─────────────────────────────────────── │ │
└──────────────┘ ④ 验证通过,返回加密数据包 spd(AES-CBC) └──────────────┘
⑤ 用会话密钥解密 spd → 拿到 PET 令牌 → 调 loginDelegates 换取 searchPartyToken
密码只在客户端被用到一次:先用服务端返回的盐值做 PBKDF2 派生(encrypt_password 函数),再完成 SRP 证明。若账号需要 2FA,会触发短信验证码(sms 模式)或受信任设备确认(trusted_device 模式)。
认证成功后,searchPartyToken 会被缓存进 auth.json,后续拉取位置直接复用——这就是"免密"二字的由来。整个密钥绑定过程在 Web 端只需导入一次标签的 JSON 密钥文件:
📡 从 SRP 会话到轨迹数据库:位置拉取闭环
拿到 Anisette 令牌和 searchPartyToken 后,拉取流程就清晰了。request_reports.py 依次做三件事:
- 批量拉取:向
gateway.icloud.com/acsnservice/fetch发起异步 POST(100 并发信号量),按标签 ID 查询时间段内的位置报告; - 解密:payload 是密文,脚本用标签私钥做 ECDH 密钥交换(SECP224R1 曲线)推导 AES-GCM 密钥,解出纬度、经度、时间戳;
- 入库:结果写入本地
reports.db(SQLite),表结构与密钥映射keyMap自动建好。
request_reports.mjs 用 node-cron 每 5 分钟调度一次 Python 脚本;server.mjs 则提供带限流的 /query API 供 Web 前端查询。最终呈现效果如下——左侧轨迹点模式,右侧热点模式(常去的地方颜色更深):
🚀 快速部署指南:四步跑通 Anisette Server 与 iCloud 认证
把全链路串起来(细节以 README.md 为准):
| 步骤 | 操作 | 关键文件 |
|---|---|---|
| 1 | 创建 Docker 网络并启动 Anisette Server(6969 端口) | dadoum/anisette-v3-server 镜像 |
| 2 | 生成标签密钥并放入 keys 目录 | keygen/generate_keys.py |
| 3 | 安装 Python 依赖,手动跑一次测试登录 | request_reports.py |
| 4 | 安装 Node.js 与 PM2,让两个服务常驻 | server.mjs |
三个要点值得留意:
- Apple ID 要求:必须是在实体 iOS 设备上注册、启用短信 2FA 的账号,建议使用实验用的新 ID,避免影响主账号;
- 多密钥滚动:
generate_keys.py -n 50可批量生成滚动密钥,标签会定期更换蓝牙 MAC 地址(与苹果 AirTag 同款机制),位置更新更频繁,但功耗也略增; - 拉取频率别太激进:默认每 5 分钟一次已经足够,改 cron 表达式即可调整。
首次使用别忘了给标签装电池并撕掉绝缘片(2032 圆形款按住后盖顺时针旋转即可打开):
⚠️ 避坑指南:iCloud 认证最常见的 3 个报错
gsa_authenticate抛 InvalidFileException:多半是当前服务器 IP 被苹果限制。用curl -k https://gsa.apple.com/grandslam/GsService2 -v自检——返回401正常,返回503则需更换服务器 IP;- 2FA 阶段收不到短信:如果该 Apple ID 还登录在别的苹果设备上,可能拦截短信,先在原设备上退出;
- Anisette Server 连不上:后端默认请求
localhost:6969,确认容器在运行、端口映射正确,可用docker logs anisette查看日志。
✅ 写在最后
- Anisette Server 解决了"设备护照"问题——纯 Linux 服务器也能通过苹果设备校验;
- SRP 免密登录 解决了"密码安全"问题——密码从不上网,令牌缓存实现无人值守;
- 定期拉取 + 本地数据库 解决了"7 天留存"限制——轨迹永久保存,支持任意时间段查询、热点图与 GPX 导出。
Anisette Server、SRP 认证与 node-cron 调度这套组合,让 DIY AirTag 以极低的硬件成本拥有了"永久轨迹记录"能力。如果你也想让定位标签真正服务于自己的 Find My 网络,不妨从部署 Anisette Server 这一步开始。
【免费下载链接】NinjiaTag-backend 项目地址: https://gitcode.com/gh_mirrors/ni/NinjiaTag-backend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考








