fix(device): 设备注册绑定接口添加 PoP 验签,照片下载改为设备端本地解密

This commit is contained in:
TongTongStudio
2026-08-24 21:32:22 +08:00
parent 417c4989f7
commit dbb75658a6
38 changed files with 2300 additions and 761 deletions

View File

@@ -66,8 +66,10 @@
设备端 后端 用户端
│ │ │
│── 生成 TEE 密钥对 ──────────│ │
│── POST /api/device/register │ │
{sn, publicKey} ──│ │
│── GET /api/device/challenge│ │
◄── {challenge} ────────────│ │
│── POST /api/device/register│ │
│ {sn,pubKey,challenge,sig}──►│── PoP 验签(challenge,sig) │
│ │── 存储 device(sn, pubKey) │
│◄── {deviceId} ─────────────│ │
│ │ │
@@ -100,8 +102,10 @@
设备端(新) 后端 用户端
│ │ │
│── 新 TEE 密钥对 │ │
│── POST /api/device/register │ │
{sn, newPubKey} ──►│(旧设备自动停用)
│── GET /api/device/challenge │ │
◄── {challenge} ─────────────│
│── POST /api/device/register │ │
│ {sn,newPubKey,challenge,sig}►│PoP 验签 + 旧设备自动停用) │
│◄── {newDeviceId} ───────────│ │
│ │ │
│ │◄── POST /api/device/sms/send │
@@ -336,14 +340,15 @@ TEE 密钥是「**门禁卡**」UK / DEK 才是「**保险柜钥匙**」。
### 数据持久化说明JPA + MySQL
设备状态、用户、照片索引已落库,**服务重启 / App 重启均不丢失注册与绑定状态**
设备状态、用户、照片归属已落库,**服务重启 / App 重启均不丢失注册与绑定状态**
| 表名 | 对应实体 | 存储内容 |
|---|---|---|
| `device` | `Device` | 设备注册/绑定状态SN 唯一、公钥、userId、active |
| `app_user` | `User` | 用户 + UK + 登录密码 |
| `encrypted_photo` | `EncryptedPhoto` | 照片元数据(密文仍落盘 `uploads/` |
| `user_photo` | `UserPhoto` | 用户 ↔ 照片索引 |
| `encrypted_photo` | `EncryptedPhoto` | 照片元数据 + 归属用户(密文仍落盘 `uploads/` |
> 注:早期版本存在 `user_photo` 关联表(`UserPhoto` 实体),已废弃。照片归属统一由 `encrypted_photo.user_id` 承担,查询复用 `findByUserIdOrderByUploadTimeAsc`。
- 数据库脚本:`springboot-server/sql/schema.sql`(含建库建表 DDL
- 依赖 `spring.jpa.hibernate.ddl-auto=update` 会在启动时自动建表,也可手动执行 `schema.sql`。
@@ -370,11 +375,11 @@ TEE 密钥是「**门禁卡**」UK / DEK 才是「**保险柜钥匙**」。
| Method | Path | 说明 |
|---|---|---|
| GET | `/api/device/status?sn=xxx` | 查询设备注册/绑定状态App 启动复用,免重复注册绑定) |
| POST | `/api/device/register` | 设备注册SN + 公钥,幂等:同 SN 同公钥返回原 deviceId |
| POST | `/api/device/register` | 设备注册SN + 公钥 + PoP 验签 `{challenge, signature}`,幂等:同 SN 同公钥返回原 deviceId |
| POST | `/api/photo/upload` | 上传加密照片(设备签名验签) |
| POST | `/api/photo/recover` | 恢复后获取照片 DEK |
> **注册/绑定幂等说明**`/api/device/register` 对「同一 SN + 相同公钥」幂等——App 重启后重复注册不会生成新 deviceId也不会误停用自己仅当公钥变化恢复出厂时才停旧换新。App 启动时建议先调 `GET /api/device/status?sn=xxx`,若 `registered=true` 且 `bound=true`,直接复用返回的 `deviceId`/`userId`,跳过注册与绑定。
> **注册/绑定幂等说明**`/api/device/register` 对「同一 SN + 相同公钥」幂等——App 重启后重复注册不会生成新 deviceId也不会误停用自己仅当公钥变化恢复出厂时才停旧换新。注册必须携带 PoP先 `GET /api/device/challenge`,再用 TEE 私钥对 challenge 签名),服务端验签通过才允许注册,防止攻击者用自己公钥冒名注册受害者 SNP0-1 修复)。App 启动时建议先调 `GET /api/device/status?sn=xxx`,若 `registered=true` 且 `bound=true`,直接复用返回的 `deviceId`/`userId`,跳过注册与绑定。
### 用户端(需要登录 Token