本文依据仓库 docs/security-model.md 整理,说明 LockPass 的密钥派生、保险库解锁、受信任设备、安全存储与密文同步流程。
**核心结论:**LockPass 的服务器只负责账号认证、设备管理和密文分发,不持有保险库解密凭据。主密码、安全密钥、unlockKey、vaultKey 和条目明文均不上传服务器。
1. 一、核心安全原则
- 主密码和密钥明文只在客户端内存中短暂存在;条目明文只在已解锁会话中出现。
- 主密码与安全密钥共同通过带版本参数的 Argon2id 派生
unlockKey,二者缺一不可。 vaultKey由密码学安全随机源生成,持久化时必须保存为wrappedVaultKey。- 条目、附件索引、备份包和密钥包统一使用 AES-256-GCM 加密并认证。
- 服务器和普通本地存储只保存密文、版本信息及白名单内的同步元数据。
- 密文格式、KDF 参数、本地 schema、服务器 schema 和同步协议均带版本。
- 默认解锁不依赖 Windows Hello、Windows PIN、指纹或人脸,也不保留免主密码解锁材料。
2. 二、密钥层级与加密流程
密钥 | 来源与用途 | 保存规则 |
|---|---|---|
主密码 | 用户记忆并在解锁时输入;参与派生 | 不保存、不上传 |
安全密钥(Secret Key) | 客户端生成的高熵随机密钥;与主密码共同派生 | 用户离线备份;受信任设备安全保存;不上传 |
| 通过 Argon2id 派生;用于解开 | 只在一次解锁过程中短暂存在 |
| 创建保险库时随机生成;用于加解密条目和附件 | 只在已解锁会话内存在 |
| 使用 | 可保存到本地密文库和服务器 |
主密码和安全密钥不是普通字符串拼接。KDF 输入包含域隔离标签与长度前缀;主密码先做 NFKC normalization 和 UTF-8 编码。修改主密码时只需用新的 unlockKey 重新包裹 vaultKey,不需要重加密全部条目。
3. 三、首次启用或新设备恢复
- 用户先登录服务器账号,再输入主密码和安全密钥。
- 客户端完整执行 Argon2id,并用 AES-256-GCM 验证、解开
wrappedVaultKey。 - 只有解锁成功后,桌面端才把安全密钥写入系统安全存储。
- Web 端生成不可导出的 AES-256-GCM 设备密钥,加密安全密钥后把密文保存到 IndexedDB。
- 当前设备或浏览器被标记为受信任设备;主密码、
unlockKey和vaultKey始终不持久化。
4. 四、受信任设备日常解锁
“快速解锁”只代表用户通常只需输入主密码,并不代表免主密码。客户端仍会读取或解开安全密钥并完整执行 Argon2id。
安全密钥不能单独解锁保险库,也不能找回或重置主密码。丢失所有受信任设备和离线保存的安全密钥后,服务器无法恢复保险库内容。
5. 五、加密与存储边界
- AES-256-GCM 的 AAD 绑定用途、对象 ID、保险库或账号范围、格式版本、密钥 ID 和 revision。
- 解密时必须使用与加密时完全相同的 AAD,防止密文被调包到其他条目、保险库或账号。
- 同一
keyId下不得复用 nonce;nonce 使用密码学安全随机源生成的 96-bit 值。 - 禁止使用
Math.random、时间戳、对象 ID 或 revision 单独生成 nonce。
位置 | 允许保存 | 禁止保存 |
|---|---|---|
系统安全存储 | 当前账号的安全密钥 | 主密码、 |
受信任浏览器 IndexedDB | 不可导出的设备密钥、安全密钥密文和必要绑定元数据 | 安全密钥明文、主密码、会话密钥、条目明文 |
普通 app data / SQLite | KDF 参数、 | 安全密钥明文、主密码、会话密钥、条目明文 |
服务器 / PostgreSQL |
| 主密码、安全密钥、 |
解锁会话内存 |
| 任何跨锁定或跨进程重启的持久化 |
加密备份包 | 密文 envelope、加密 manifest 和必要版本信息 | 安全密钥及其他解密密钥的明文 |
6. 六、加密同步流程
服务器账号用于身份验证、设备管理和密文分发,不是保险库解密凭据。联网时修改立即加密上传;断网时先进入本机密文待保存队列,恢复联网后先上传本机修改,再拉取服务器变化。
客户端以本地可信 checkpoint 检测回滚:event cursor 不得低于已确认高水位;同一对象的 revision 不得低于本地已见最大值;envelope AAD 中的对象 ID、保险库 ID、格式版本和 revision 必须与外层同步元数据一致。新设备首次同步只能建立基线,或由另一台可信设备、离线备份交叉校验。
7. 七、客户端信任边界
- 共享的
@lockpass/cryptoprovider 负责 Argon2id、AES-256-GCM、密文 envelope 与会话状态。 - 页面组件只传递随机
sessionId,不直接持有vaultKey;锁定后会话和界面明文必须清理。 - Rust 负责系统安全存储、本地数据库和文件访问。Windows 解锁只读取 Credential Manager 中的安全密钥。
- 桌面 WebView 只加载随安装包发布的本地资源,不加载远程 script,也不使用动态代码执行能力;发布包和更新包必须签名并验证。
- 浏览器扩展是独立客户端,复用同一加密与同步协议,但不能把完整保险库或长期密钥材料发送给 Content Script。
8. 八、主要威胁与剩余风险
威胁 | 处理方式与剩余风险 |
|---|---|
本地 SQLite 或服务器泄露 | 只暴露密文及非敏感元数据;服务器没有解密密钥,不能直接解密条目。 |
服务器返回旧数据 | 已使用设备依据本地 checkpoint 检测;新设备首次同步只能建立基线。 |
锁定后旁人操作 | 锁定销毁 provider 会话和界面明文;再次进入必须输入主密码并运行 Argon2id。 |
受信任浏览器 Profile 失陷 | 攻击者可能调用不可导出设备密钥解开安全密钥,但仍需主密码;可结合密钥包离线猜测主密码。 |
终端恶意软件 | 系统安全存储不能抵抗键盘记录、进程注入、同用户凭据 API 滥用或已解锁会话窃取。 |
日志泄露 | 禁止记录主密码、token、安全密钥、解密结果和条目明文。 |
**安全不变量:**任何新增功能若要求服务端保存新的明文字段,必须先更新明文白名单,说明泄露范围与用户可关闭方式;任何 schema 或密文格式变更都必须带版本并提供逐步迁移测试。
