# 数据安全升级与迁移

> 将已有 DBX 数据升级到加密 Secret Store 的完整指南。

Source: https://dbxio.com/cn/docs/data-security-migration

Language: zh-CN

Relative links resolve against https://dbxio.com/cn/docs/data-security-migration.



如果当前安装已经保存连接、密码、插件凭据、AI 提供商密钥、Tunnel 凭据或同步凭据，请先完成数据安全升级再使用 DBX。升级前请备份完整数据目录，并保留原有加密密钥。

本版本会把历史明文字段和 JSON 配置中的敏感值迁移到 DBX 加密 Secret Store。每个数据目录只需执行一次。向导会展示迁移范围，创建可回滚备份，执行迁移和验证，并在你明确删除前保留备份。

## 本次升级会改变什么

迁移覆盖以下敏感数据：

* 数据库连接密码、SSH 凭据、私钥口令和 HTTP Tunnel 密钥；
* 标记为 secret 的插件连接字段；
* AI 提供商凭据；
* SSH 和其他 Tunnel 配置；
* WebDAV 及其他同步凭据；
* 历史 `connections.json`、`secrets.json` 和相关 JSON 文件。

连接和提供商的公开配置仍保留在普通配置中。敏感值改为加密字段，只能通过本机 Secret Store 解密。原始值不会上传、写入日志或出现在迁移诊断中。

迁移使用固定 ID `secret-store-v1`，并记录以下状态：

| 状态             | 含义           | 处理方式               |
| -------------- | ------------ | ------------------ |
| `pending`      | 需要迁移，或环境仍需修复 | 查看向导并处理密钥或文件问题     |
| `running`      | 正在备份或迁移      | 等待完成，不要替换数据目录      |
| `failed`       | 检查、写入或验证失败   | 查看脱敏错误，修复后点击“重试迁移” |
| `succeeded`    | 迁移和验证完成      | 测试 DBX，之后可选择删除迁移备份 |
| `not_required` | 没有需要转换的历史数据  | 直接进入 DBX           |

## 升级前准备

1. 退出 DBX，复制完整数据目录，包括 `dbx.db`、WAL 文件、JSON 配置文件和 `.dbx` 目录。
2. 确认当前部署使用的密钥来源。已有密文时绝对不要轮换、删除或替换密钥。
3. 确认运行 DBX 的账户可以读写数据目录，并能访问系统凭据库或外部密钥。
4. 如果数据目录位于挂载卷，升级前先确保该卷会持久化。
5. 不要只复制 `dbx.db` 到另一种操作系统。跨设备请使用 DBX 加密导出/导入。

迁移备份是额外的回滚副本，不能替代正常备份策略。

## 按部署方式升级

### 桌面端应用

桌面版使用操作系统凭据库：

| 平台      | 密钥来源                           |
| ------- | ------------------------------ |
| macOS   | Keychain，以及构建版本支持的平台兼容密钥       |
| Windows | Credential Manager             |
| Linux   | Secret Service；没有可用提供者时配置持久化密钥 |

升级步骤：

1. 安装新版本，不要删除已有配置目录。
2. 启动 DBX，并在提示时允许访问 Keychain、Credential Manager 或 Secret Service。
3. 在“数据安全升级”向导中查看统计和历史文件列表。
4. 点击“开始迁移”，等待备份、迁移和验证完成。
5. 完成页出现后，打开代表性的连接，并验证插件、AI 提供商、Tunnel 和同步功能。
6. 验证通过前保留备份；确认不再需要回滚后再点击“删除迁移备份”。

迁移期间主界面和普通业务命令会保持阻塞。状态、开始、重试、诊断和备份清理请求仍可用，向导才能恢复未完成的升级。

### Docker 和 `dbx-web`

数据库、历史文件和托管密钥必须使用同一个持久化数据卷。默认托管密钥位置是：

```text
${DBX_DATA_DIR}/.dbx/secret.key
```

Docker 升级步骤：

1. 停止旧容器，备份命名卷或绑定的 `DBX_DATA_DIR`。
2. 新容器继续把同一个卷挂载到同一个路径。
3. 如果使用生产环境密钥，在启动新镜像前挂载密钥并设置 `DBX_SECRET_KEY_FILE`：

```yaml
services:
  dbx:
    image: t8y2/dbx:latest
    environment:
      DBX_DATA_DIR: /app/data
      DBX_SECRET_KEY_FILE: /run/secrets/dbx_secret_key
    secrets:
      - dbx_secret_key
    volumes:
      - dbx-data:/app/data

secrets:
  dbx_secret_key:
    file: ./dbx_secret_key
```

4. 启动新容器并打开 Web UI。业务 API 开放前会先显示迁移向导。
5. 执行迁移，等待成功页出现，并通过 Web UI 验证代表性连接。
6. 始终把数据卷和密钥一起保留；验证通过后再删除迁移备份。

也可以由密钥管理系统提供 `DBX_SECRET_KEY`，不使用 `DBX_SECRET_KEY_FILE`。显式配置优先于数据目录托管密钥；如果显式密钥不可读或格式错误，DBX 不会静默回退到其他密钥。

迁移未完成时，Web API 只允许迁移状态、开始、重试、ping、认证和备份清理。其他 API、MCP 路由和业务操作会返回 `423 DATA_MIGRATION_REQUIRED`。

### 直接运行二进制或 systemd 服务

1. 停止服务，备份 `DBX_DATA_DIR` 指向的目录。
2. 确认服务账户能保留 `${DBX_DATA_DIR}/.dbx/secret.key`，或配置稳定的 `DBX_SECRET_KEY_FILE`/`DBX_SECRET_KEY`。
3. 替换二进制并重启服务。
4. 打开 `dbx-web` 提供的 Web UI，完成迁移向导。
5. 使用 systemd 时，把密钥环境放在受保护的环境文件或凭据机制中，不要把生产密钥放在所有用户可读的 unit 文件里。
6. 删除迁移备份前，先验证连接和相关集成。

### CLI 和 MCP

CLI 与独立 MCP 只检查迁移状态和已有密钥，不会创建密钥，也不会执行历史数据迁移。将 `DBX_DATA_DIR` 指向原数据目录，先通过桌面端或 `dbx-web` 完成迁移；在此之前，依赖业务数据的命令会返回 `DATA_MIGRATION_REQUIRED`。

## 密钥管理规则

DBX 有两条相互独立的密钥边界：

| 密钥                 | 用途                   | 存放位置                  | 是否通过同步复制         |
| ------------------ | -------------------- | --------------------- | ---------------- |
| 本地 Secret Store 密钥 | 加密本机 `dbx.db` 中的敏感值  | 系统凭据库、数据目录托管密钥或环境变量密钥 | 否                |
| 同步口令               | 加密导出/导入包中的敏感 payload | 用户为该同步包输入的口令          | 只作为同步包保护，不作为本地密钥 |

数据目录托管密钥只有在迁移或首次写入敏感值时才会创建。它必须与 `dbx.db` 一起备份。密钥和数据库在同一卷中，只能保护静态数据内容，不能防止整个数据卷被复制后泄露。

已有密文时使用新密钥会导致数据无法解密。正确做法是恢复原密钥，不要生成替代密钥。

## 迁移内部流程

存储层把迁移分成三个阶段：

```text
open_unmigrated()
  -> 打开 SQLite 并初始化必要 schema，不修改历史数据
inspect_data_migration()
  -> 只读扫描数据库行、JSON 文件和密钥可用性
start_data_migration()/retry_data_migration()
  -> 创建备份、迁移、验证并记录最终状态
```

写入数据前，DBX 会创建权限受限的 `dbx-secret-migration-<uuid>/` 目录，存放一致性 SQLite 备份和存在的历史 JSON 文件。SQLite 使用备份 API 以保留 WAL 状态；备份失败时不会开始迁移。

迁移把敏感字段写入本地 Secret Store，公开 JSON 只保留非敏感配置，并验证旧明文列为空且所有密文都能解密。历史 JSON 遵循“导入、验证、最后改名”顺序；只有成功后才改成 `.bak`。解析或验证失败时原文件仍保留，方便修复和重试。后续步骤失败时会先恢复 SQLite 备份，再记录 `failed`。

预检查只返回数量、状态、非敏感提供商名称和文件名，不返回密码、Token、私钥、密钥内容或密钥路径。扫描统计带有源数据指纹，避免旧缓存让成功迁移再次显示为未完成。

## 迁移成功后

1. 测试你使用的每种数据库至少一个连接。
2. 测试插件连接、AI 提供商、SSH/Tunnel 配置和包含凭据的同步操作。
3. 重启 DBX 或容器，确认下一次启动直接进入主界面。
4. 这些检查通过前保留迁移备份。
5. 确认不再需要回滚后，点击“删除迁移备份”。启动门禁允许发送清理请求，但存储层仍会强制要求记录状态为 `succeeded`。

保留备份不会阻塞后续启动。删除备份不可逆；如果仍需要恢复迁移前状态，请保留普通数据备份。

## 失败处理

### 向导显示迁移失败

原始数据和迁移备份会保留。阅读向导错误，修复环境后点击“重试迁移”。常见原因包括：

* 没有允许访问 Keychain、Credential Manager 或 Secret Service；
* `.dbx/secret.key` 缺失或不可读；
* `DBX_SECRET_KEY_FILE` 或 `DBX_SECRET_KEY` 已更换；
* 历史 JSON 格式错误；
* 没有足够权限或磁盘空间创建备份；
* 历史值无法通过验证。

排查期间不要删除 `dbx.db`、WAL、历史 JSON 或迁移目录。

### 重启后向导再次出现

导出脱敏诊断，检查 `state`、`needsMigration`、`errorCode`、`backupPath` 和统计字段。成功迁移应为 `succeeded` 或 `not_required`。如果启动之间更换了密钥或数据目录，先恢复原来的配对关系再重试。

### 密钥不可用

桌面端请允许 DBX 访问系统凭据库。Web、Docker 或二进制服务请确认数据目录挂载正确，且显式密钥配置可读。已有加密配置不能通过创建新密钥解决。

### 连接密码消失

确认应用使用的是升级前相同的数据目录和密钥。如果连接设置为 `save_password=false`，迁移会按设计不恢复主密码。确认配置目录和密钥正确后，再通过连接编辑器重新输入密码。

### 删除备份失败

保留备份并重试，同时检查迁移状态是否为 `succeeded`、数据目录是否可写，以及备份文件是否被手动修改。清理过程会在删除前校验清单路径和文件摘要。

## 跨设备迁移不是本次升级

不要通过复制 `dbx.db` 在不同操作系统之间搬迁配置。本地密钥属于源设备，请使用加密配置导出/导入：

1. 分离导出公开配置和敏感值。
2. 使用用户提供的同步口令保护敏感 payload。
3. 在目标设备导入。
4. 使用目标设备自己的本地 Secret Store 密钥重新加密。

同步口令错误、ID 冲突或任一字段失败时，不会提交半成品导入结果。

## 验证清单

* [ ] 已创建完整的升级前数据目录备份。
* [ ] 原有本地密钥或外部托管密钥仍然保留。
* [ ] 向导以 `succeeded` 完成，或状态为 `not_required`。
* [ ] 代表性连接和相关集成均可用。
* [ ] 重启后不再阻塞在迁移向导。
* [ ] 已保留迁移备份，或在验证后明确删除。
* [ ] 跨设备迁移使用加密导出/导入，没有直接复制数据库。

状态机、存储实现和开发者测试矩阵请参阅 [DBX 数据安全升级与迁移参考](https://github.com/t8y2/dbx/blob/main/docs/data-security-migration.zh-CN.md)。

