版本:2026-08 范围:Senvra 备份与还原 V1,写入格式以
SNVRBKP3为准,并保留对SNVRBKP2的只读兼容。 目标:让用户可以安全地迁移或长期保存数据,同时避免备份文件、错误提示、交互文案泄露空间身份。
1. 方案概览
Senvra 的备份设计不是简单地把数据库和媒体文件打包导出,而是把备份看作一次独立的加密发布流程。导出时不落地明文临时文件,还原时不直接覆盖空间,而是经过校验、解密、查重、临时导入和原子提交几个阶段。
This diagram could not be rendered. Its source is still available below.
View diagram source
flowchart LR
A[当前空间数据] --> B[导出清单构建]
B --> C[逐项读取媒体与元数据]
C --> D[分块 AES-256-GCM 加密]
D --> E[SNVRBKP3 流式写入]
E --> F[原子落盘为 .senvrabackup]
G[.senvrabackup] --> H[Header 与 AAD 校验]
H --> I[凭据派生与解密]
I --> J[中性查重]
J --> K[临时导入区]
K --> L[原子提交到当前空间]
核心原则:
| 原则 | 设计选择 |
|---|---|
| 不泄露来源空间 | 外层 Header 禁止写入 sourceSpaceID、scope、backupID 等可识别字段 |
| 不暂存明文 | 导出和还原均采用流式处理,明文只存在于内存中的短生命周期缓冲 |
| 不跨空间恢复身份 | 还原只支持“导入当前空间”,不展示“备份来自哪个空间” |
| 不信任文件结构 | Header、Manifest、Note、Attachment、Chunk 都必须被认证和归属校验 |
| 不牺牲交互隐私 | 长耗时任务显示中性的 Privacy Shield,避免露出相册内容或空间状态 |
2. 威胁模型
备份文件通常会被放进 iCloud、移动硬盘、聊天文件、NAS 或第三方网盘,暴露面比 App 沙盒更大。因此备份格式必须假设攻击者可以长期持有 .senvrabackup 文件,并反复进行离线分析。
This diagram could not be rendered. Its source is still available below.
View diagram source
mindmap
root((Backup Threat Model))
离线攻击
暴力破解密码
重放旧 Header
篡改 Manifest
身份泄露
空间 ID 暴露
文件名暴露
错误提示暴露路径
数据完整性
媒体块被替换
Note 与 Attachment 关系被伪造
导入中断留下半成品
体验风险
长任务期间露出敏感缩略图
大文件导出卡顿
低磁盘导致损坏备份
防护重点不是“文件后缀看起来私密”,而是确保备份文件在离线环境下仍然只暴露最少元信息,并且任何篡改都会在解密或导入前被发现。
3. 密钥与凭据模型
Senvra 使用双凭据模型。私密空间以用户保存的 Access Key 为基础,再叠加 Backup Password;公共空间不要求用户理解空间密钥,而是使用随机 Backup Key 来隔离备份加密材料。
This diagram could not be rendered. Its source is still available below.
View diagram source
flowchart TB
subgraph PrivateSpace[私密空间备份]
A1[Access Key] --> C1[KDF]
B1[Backup Password] --> C1
C1 --> D1[Backup Encryption Key]
end
subgraph PublicSpace[公共空间备份]
A2[Random Backup Key] --> C2[KDF]
B2[Backup Password 可选/按产品策略] --> C2
C2 --> D2[Backup Encryption Key]
end
D1 --> E[AES-256-GCM 分块加密]
D2 --> E
推荐实现约束:
| 项目 | 约束 |
|---|---|
| KDF | PBKDF2,默认 600k 迭代,并为后续 Argon2 或更高迭代预留参数字段 |
| 数据加密 | AES-256-GCM |
| 分块大小 | 默认 8 MiB,每块独立 nonce 与 tag |
| 认证数据 | Header canonical bytes、版本号、chunk index、manifest digest 等纳入 AAD |
| 密钥生命周期 | 派生密钥只在任务内存活,任务取消或失败后立即释放引用 |
4. SNVRBKP3 文件结构
SNVRBKP3 是当前写入格式。它的关键变化是强化 Header/AAD 认证,并将 Manifest、Note、Attachment 的归属关系纳入导入前校验。
This diagram could not be rendered. Its source is still available below.
View diagram source
flowchart LR
A[Magic<br/>SNVRBKP] --> B[Version<br/>3]
B --> C[Header Length]
C --> D[Public Header]
D --> E[Salt<br/>KDF Params]
E --> F[Manifest Digest]
F --> G[Encrypted Manifest]
G --> H[Encrypted Chunks]
H --> I[Final Auth Trailer]
外层 Header 只允许放置解密和兼容所需的中性字段。
| 允许字段 | 用途 |
|---|---|
magic | 识别备份文件类型 |
version | 选择解析器和兼容路径 |
kdf | 描述 KDF 算法与参数 |
salt | 密钥派生随机盐 |
chunkSize | 流式解密的块大小 |
createdAt | 可选,中性时间信息 |
| 禁止字段 | 风险 |
|---|---|
sourceSpaceID | 直接泄露来源空间身份 |
| scope / space type | 暗示用户的私密空间结构 |
backupID | 可能被跨文件关联追踪 |
| 原始文件名 / 系统路径 | 可能泄露内容语义或设备信息 |
5. 导出流程
导出流程以“清单先行、流式写入、失败清理”为主线。系统先构建待导出的逻辑清单,再逐项读取数据库记录和媒体文件,边读边加密写入目标文件,不创建明文压缩包。
This diagram could not be rendered. Its source is still available below.
View diagram source
sequenceDiagram
participant UI as Backup UI
participant App as AppModel
participant Store as VaultStore
participant Crypto as Crypto Pipeline
participant File as Backup Writer
UI->>App: 用户确认导出
App->>Store: 请求快照与导出清单
Store-->>App: Notes / Attachments / Media refs
App->>Crypto: 初始化 KDF 与 Header AAD
loop 每个媒体或元数据块
App->>Store: 流式读取
Store-->>Crypto: 明文缓冲
Crypto-->>File: 密文块 + tag
end
File->>File: fsync + 原子 rename
App-->>UI: 完成或中性失败信息
性能策略:
| 场景 | 策略 |
|---|---|
| 大媒体文件 | 固定 8 MiB 分块,避免一次性读入内存 |
| 大量小附件 | 批量构建清单,减少数据库往返 |
| 低磁盘 | 导出前预估空间,导出中监控写入失败并清理临时文件 |
| 任务取消 | 停止读取、销毁密钥引用、删除未完成临时备份 |
| App 失活 | 进入中性遮罩,避免任务期间暴露内容缩略图 |
6. 还原流程
还原不是“恢复一个空间”,而是“把备份内容导入当前空间”。这个产品边界可以避免用户从 UI 文案或数据结构里推断出备份来源空间。
This diagram could not be rendered. Its source is still available below.
View diagram source
flowchart TD
A[选择 .senvrabackup] --> B{Magic / Version 合法?}
B -- 否 --> X[中性失败提示]
B -- 是 --> C[读取 Header 与 KDF 参数]
C --> D[输入 Access Key / Backup Password]
D --> E{Header AAD 校验通过?}
E -- 否 --> X
E -- 是 --> F[解密 Manifest]
F --> G{归属关系校验}
G -- 否 --> X
G -- 是 --> H[中性查重]
H --> I[写入临时导入区]
I --> J{全部块校验通过?}
J -- 否 --> Y[清理临时导入区]
J -- 是 --> K[原子提交到当前空间]
K --> L[完成]
导入前必须完成三类检查:
| 检查 | 目的 |
|---|---|
| Header/AAD 认证 | 防止攻击者替换版本、KDF 参数或 Header |
| Manifest digest | 防止清单被替换、裁剪或重排 |
| Note/Attachment 归属 | 防止附件被挂到错误 Note,或伪造孤儿记录 |
查重逻辑必须保持中性:可以判断“已存在相同内容”并跳过重复项,但不展示来源空间、原始路径、原始文件名等敏感上下文。
7. Privacy Shield
备份和还原属于长耗时任务。用户一旦进入后台、锁屏、切换 App、触发录屏风险,界面应该切换到中性的 Privacy Shield,而不是继续展示相册网格、文件名或空间状态。
This diagram could not be rendered. Its source is still available below.
View diagram source
stateDiagram-v2
[*] --> Idle
Idle --> Exporting: 开始备份
Idle --> Importing: 开始导入
Exporting --> Shielded: App 失活 / 锁屏 / 风险状态
Importing --> Shielded: App 失活 / 锁屏 / 风险状态
Shielded --> Exporting: 回到安全前台
Shielded --> Importing: 回到安全前台
Exporting --> Finished
Importing --> Finished
Exporting --> Failed
Importing --> Failed
Failed --> Idle
Finished --> Idle
界面文案应保持中性,例如:
| 不推荐 | 推荐 |
|---|---|
| 正在恢复私密空间 | 正在导入备份 |
| 来自 XXX 空间的备份已恢复 | 已导入可用内容 |
文件 IMG_0001.mov 解密失败 | 部分内容无法导入 |
/var/mobile/... 写入失败 | 存储空间不足或文件不可用 |
8. 原子化与失败恢复
导入流程必须保证“要么全部提交,要么看起来什么都没发生”。用户不应该在失败后看到半张图片、半条 Note 或孤立附件。
This diagram could not be rendered. Its source is still available below.
View diagram source
flowchart LR
A[创建导入事务] --> B[写临时数据库记录]
B --> C[写临时媒体文件]
C --> D[校验所有 tag 与 digest]
D --> E{校验通过?}
E -- 是 --> F[批量提交记录]
F --> G[移动媒体到正式目录]
G --> H[提交事务]
E -- 否 --> I[回滚数据库]
I --> J[删除临时媒体]
失败处理规则:
| 阶段 | 失败动作 |
|---|---|
| 凭据错误 | 不暴露是 Access Key 还是 Password 错,只提示无法打开备份 |
| Header 校验失败 | 停止解析,避免继续读取被篡改结构 |
| 分块解密失败 | 删除当前临时文件,标记任务失败 |
| 导入提交失败 | 回滚数据库事务,并清理临时媒体目录 |
| 用户取消 | 尽快停止 I/O,清理临时产物,界面回到安全状态 |
9. 兼容策略
This diagram could not be rendered. Its source is still available below.
View diagram source
flowchart LR
A[SNVRBKP2<br/>只读兼容] --> B[SNVRBKP3<br/>当前写入格式]
B --> C[Future<br/>新 KDF / 分块索引 / 压缩策略]
兼容原则:
| 版本 | 策略 |
|---|---|
SNVRBKP3 | 默认导出格式,完整安全能力 |
SNVRBKP2 | 只读导入,不再生成 |
| 未知更高版本 | 不尝试降级解析,提示当前版本暂不支持 |
| 损坏或伪造版本 | 返回中性失败,不展示底层异常 |
10. 验收红线
上线前至少满足以下红线:
- 外层 Header 不包含
sourceSpaceID、scope、backupID、原始文件名、系统路径。 - 导出流程不创建明文 zip、明文 tar、明文 sqlite 副本或可恢复的明文临时目录。
SNVRBKP3的 Header、Manifest、Chunk 均参与认证,任意篡改都能失败。- Note 与 Attachment 的归属关系在导入前验证,不能出现跨记录挂载。
- 还原只能导入当前空间,UI 不出现“恢复到原空间”或“来自某空间”的暗示。
- 导入提交具备事务边界,失败后不能留下半成品。
- 低磁盘、强制中断、用户取消后,会清理临时文件。
- 错误提示不包含文件名、路径、空间名、内部 ID 或系统异常原文。
- 长耗时任务在失活、锁屏、录屏风险下进入 Privacy Shield。
11. 用户路径
This diagram could not be rendered. Its source is still available below.
View diagram source
journey
title 用户备份与迁移体验
section 导出
选择备份: 5: 用户
设置备份密码: 4: 用户
保存 Access Key 或 Backup Key: 3: 用户
等待导出完成: 4: 用户
section 保存
把 .senvrabackup 放到可信位置: 4: 用户
记录凭据: 3: 用户
section 导入
选择备份文件: 5: 用户
输入凭据: 3: 用户
导入当前空间: 5: 用户
体验设计的重点是让用户明确知道两件事:
- 备份文件本身已经加密,但丢失凭据就无法恢复。
- 还原会导入当前空间,不会在 UI 上暴露备份原本属于哪个空间。
12. 实现检查清单
| 模块 | 检查项 | 状态 |
|---|---|---|
| Backup Writer | 流式写入、原子 rename、失败清理 | 必须 |
| Crypto | PBKDF2 参数、AES-GCM chunk、AAD 绑定 | 必须 |
| Manifest | Digest、记录归属、版本兼容字段 | 必须 |
| Restore Pipeline | 临时导入区、查重、事务提交 | 必须 |
| UI | 中性文案、Privacy Shield、进度反馈 | 必须 |
| Error Boundary | 过滤系统路径、文件名、内部 ID | 必须 |
| Compatibility | SNVRBKP2 只读、未知版本拒绝 | 必须 |
| Disk Guard | 导出/导入前容量预检,失败后清理 | 必须 |
13. 总结
Senvra 的备份方案核心不是“导出一个文件”,而是把敏感数据从 App 沙盒带到更不可信的外部环境时,仍然保持加密、认证、低泄露和可恢复的工程边界。
这套方案用 SNVRBKP3 解决格式可信问题,用双凭据模型解决离线攻击问题,用流式加密解决明文暂存和大文件性能问题,用当前空间导入与中性文案解决身份泄露问题。最终目标是让备份文件可以长期保存、跨设备迁移,同时不让用户承担理解内部空间结构的成本。