refactor(android): 改用设备签名拦截器认证,移除 challenge 往返
设备接口统一由 AuthInterceptor 注入 Device-Sig 头完成认证,删除手动 challenge 签名流程与 transport-key 接口,注册改用本地生成 ts:nonce 做 PoP 验签。
This commit is contained in:
39
README.md
39
README.md
@@ -62,19 +62,22 @@
|
||||
|
||||
### Phase 1:设备注册 + 用户绑定
|
||||
|
||||
> **方案 A(Header 设备签名认证)**:设备不再先 `GET /api/device/challenge`。设备本地生成
|
||||
> `ts:nonce`,用 TEE 私钥对 `METHOD|path|ts|nonce` 做 RSA-PSS 签名,写入请求头
|
||||
> `Authorization: Device-Sig sn=...,ts=...,nonce=...,sig=...`;服务端 `DeviceAuthInterceptor`
|
||||
> 统一验签(时效 + nonce 防重放 + 验签),业务接口零额外往返。仅注册接口用请求内公钥做 PoP 验签。
|
||||
|
||||
```
|
||||
设备端 后端 用户端
|
||||
│ │ │
|
||||
│── 生成 TEE 密钥对 ──────────│ │
|
||||
│── GET /api/device/challenge│ │
|
||||
│◄── {challenge} ────────────│ │
|
||||
│── POST /api/device/register│ │
|
||||
│ {sn,pubKey,challenge,sig}──►│── PoP 验签(challenge,sig) │
|
||||
│── POST /api/device/register│ (challenge=ts:nonce 由设备本地生成并自签名)│
|
||||
│ {sn,pubKey,challenge,sig}──►│── PoP 验签(用请求内公钥) │
|
||||
│ │── 存储 device(sn, pubKey) │
|
||||
│◄── {deviceId} ─────────────│ │
|
||||
│ │ │
|
||||
│ │◄── POST /api/device/bind │
|
||||
│ │ {userId, sn} │
|
||||
│ POST /api/device/bind │ 每个设备接口自动携带 │
|
||||
│ (Device-Sig 头 + {userId}) ──►│── DeviceAuthInterceptor 验签│
|
||||
│ │── 绑定 userId ↔ deviceId │
|
||||
│ │◄── {ok} ────────────────────│
|
||||
```
|
||||
@@ -102,9 +105,7 @@
|
||||
设备端(新) 后端 用户端
|
||||
│ │ │
|
||||
│── 新 TEE 密钥对 │ │
|
||||
│── GET /api/device/challenge │ │
|
||||
│◄── {challenge} ─────────────│ │
|
||||
│── POST /api/device/register │ │
|
||||
│── POST /api/device/register │ (challenge=ts:nonce 本地自签名)│
|
||||
│ {sn,newPubKey,challenge,sig}►│(PoP 验签 + 旧设备自动停用) │
|
||||
│◄── {newDeviceId} ───────────│ │
|
||||
│ │ │
|
||||
@@ -372,14 +373,24 @@ TEE 密钥是「**门禁卡**」,UK / DEK 才是「**保险柜钥匙**」。
|
||||
|
||||
### 设备端(无登录,信任边界 = TEE 密钥 / SN / Recovery Token)
|
||||
|
||||
> 设备端所有接口除 `/api/device/register` 外,均由 `AuthInterceptor` 自动注入
|
||||
> `Authorization: Device-Sig sn=...,ts=...,nonce=...,sig=...` 完成设备签名认证(方案 A,
|
||||
> 零 challenge 往返),请求体只含业务字段。
|
||||
|
||||
| Method | Path | 说明 |
|
||||
|---|---|---|
|
||||
| GET | `/api/device/status?sn=xxx` | 查询设备注册/绑定状态(App 启动复用,免重复注册绑定) |
|
||||
| POST | `/api/device/register` | 设备注册(SN + 公钥 + PoP 验签 `{challenge, signature}`,幂等:同 SN 同公钥返回原 deviceId) |
|
||||
| POST | `/api/photo/upload` | 上传加密照片(设备签名验签) |
|
||||
| POST | `/api/photo/recover` | 恢复后获取照片 DEK |
|
||||
| POST | `/api/device/status` | 查询设备注册/绑定状态(App 启动复用,免重复注册绑定) |
|
||||
| POST | `/api/device/register` | 设备注册(SN + 公钥 + PoP 验签 `{challenge, signature}`,challenge 由设备本地生成 `ts:nonce`,幂等:同 SN 同公钥返回原 deviceId) |
|
||||
| POST | `/api/device/bind` | 绑定设备(`{userId}`,设备签名认证) |
|
||||
| POST | `/api/device/sms/send` | 发送短信验证码(设备签名认证防轰炸) |
|
||||
| POST | `/api/device/recover` | 恢复授权(短信 + SN 双因子,设备签名认证) |
|
||||
| POST | `/api/device/photos` | 本设备绑定用户的照片 ID 列表 |
|
||||
| POST | `/api/device/photos/metadata` | 本设备绑定用户的照片元数据 |
|
||||
| POST | `/api/device/photo/{photoId}/local` | 设备本地下载解密单张照片(端到端加密) |
|
||||
| POST | `/api/photo/upload` | 上传加密照片(设备签名 + 元数据验签) |
|
||||
| POST | `/api/photo/recover` | 恢复后获取照片 DEK(设备签名认证) |
|
||||
|
||||
> **注册/绑定幂等说明**:`/api/device/register` 对「同一 SN + 相同公钥」幂等——App 重启后重复注册不会生成新 deviceId,也不会误停用自己;仅当公钥变化(恢复出厂)时才停旧换新。注册必须携带 PoP(先 `GET /api/device/challenge`,再用 TEE 私钥对 challenge 签名),服务端验签通过才允许注册,防止攻击者用自己公钥冒名注册受害者 SN(P0-1 修复)。App 启动时建议先调 `GET /api/device/status?sn=xxx`,若 `registered=true` 且 `bound=true`,直接复用返回的 `deviceId`/`userId`,跳过注册与绑定。
|
||||
> **注册/绑定幂等说明**:`/api/device/register` 对「同一 SN + 相同公钥」幂等——App 重启后重复注册不会生成新 deviceId,也不会误停用自己;仅当公钥变化(恢复出厂)时才停旧换新。注册必须携带 PoP(challenge 由设备本地生成 `ts:nonce`,用 TEE 私钥签名,服务端用请求内公钥验签),防止攻击者用自己公钥冒名注册受害者 SN。App 启动时建议先调 `POST /api/device/status`,若 `registered=true` 且 `bound=true`,直接复用返回的 `deviceId`/`userId`,跳过注册与绑定。
|
||||
|
||||
### 用户端(需要登录 Token)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user