为什么DIY AirTag离不开Anisette Server?NinjiaTag苹果iCloud认证机制与SRP免密登录深度剖析

为什么DIY AirTag离不开Anisette Server?NinjiaTag苹果iCloud认证机制与SRP免密登录深度剖析

【免费下载链接】NinjiaTag-backend 【免费下载链接】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,它的工作方式是:

  1. 蓝牙标签周期性广播一个"加密身份"(密钥,实为加密后的 MAC 地址);
  2. 路人 iPhone 收到广播后,转发给 Find My 网络;
  3. 苹果服务器匹配并加密位置信息,暂存在你的 Apple ID 名下(最多约 7 天);
  4. NinjiaTag 后台通过 iCloud 认证接口登录你的 Apple ID,定期把这份数据拉取下来、解密,并永久存入本地 SQLite 数据库——这正是它能"任意时间段回溯轨迹"的关键。

相比主流产品"最多记录 7 天",NinjiaTag 支持不限时长存储、任意时间段查询、热点热图和 GPX 导出。

DIY AirTag硬件:兼容Find My网络的2032圆形蓝牙定位标签

硬件本身只是一块极简的 nRF5x 或 ST17H66 蓝牙模块(下图是一块标注了 LDO 稳压器的低成本模块,用 USB 供电即可烧录):

DIY AirTag低成本蓝牙模块:标注LDO低压差线性稳压器的最小系统

完整的硬件刷机与使用说明见 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 密钥文件:

NinjiaTag Web端物品管理界面:导入JSON密钥文件绑定DIY AirTag

📡 从 SRP 会话到轨迹数据库:位置拉取闭环

拿到 Anisette 令牌和 searchPartyToken 后,拉取流程就清晰了。request_reports.py 依次做三件事:

  1. 批量拉取:向 gateway.icloud.com/acsnservice/fetch 发起异步 POST(100 并发信号量),按标签 ID 查询时间段内的位置报告;
  2. 解密:payload 是密文,脚本用标签私钥做 ECDH 密钥交换(SECP224R1 曲线)推导 AES-GCM 密钥,解出纬度、经度、时间戳;
  3. 入库:结果写入本地 reports.db(SQLite),表结构与密钥映射 keyMap 自动建好。

request_reports.mjs 用 node-cron 每 5 分钟调度一次 Python 脚本;server.mjs 则提供带限流的 /query API 供 Web 前端查询。最终呈现效果如下——左侧轨迹点模式,右侧热点模式(常去的地方颜色更深):

NinjiaTag Web前端:DIY AirTag轨迹点与热点热图三维地图展示

🚀 快速部署指南:四步跑通 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 圆形款按住后盖顺时针旋转即可打开):

DIY AirTag 2032圆形定位标签打开后盖取出绝缘片安装示意

⚠️ 避坑指南:iCloud 认证最常见的 3 个报错

  1. gsa_authenticate 抛 InvalidFileException:多半是当前服务器 IP 被苹果限制。用 curl -k https://gsa.apple.com/grandslam/GsService2 -v 自检——返回 401 正常,返回 503 则需更换服务器 IP;
  2. 2FA 阶段收不到短信:如果该 Apple ID 还登录在别的苹果设备上,可能拦截短信,先在原设备上退出;
  3. 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 【免费下载链接】NinjiaTag-backend 项目地址: https://gitcode.com/gh_mirrors/ni/NinjiaTag-backend

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值