效率工具

给个人 Bitwarden 保险库做定期加密备份

给个人 Bitwarden 保险库做定期加密备份:脚本用 bw export --format encrypted_json --password 导出受密码保护的文件,校验确实是加密格式,只保留最近 12 份,文件权限 600。万一账号出问题,用备份密码就能导入任意 Bitwarden 账号恢复。

BINBHO · 图文教程

给个人 Bitwarden 保险库做定期加密备份:脚本用 bw export --format encrypted_json --password 导出受密码保护的文件,校验确实是加密格式,只保留最近 12 份,文件权限 600。万一账号出问题,用备份密码就能导入任意 Bitwarden 账号恢复。

先看清成品

本机安装了 Bitwarden CLI 2026.10.0,确认了 bw export 支持 encrypted_json 和 --password;并从 CLI 源码确认受密码保护的导出文件包含 "encrypted": true 和 "passwordProtected": true。备份脚本用假的 bw 命令跑了 5 项测试全部通过(保留份数、权限、拦截未加密导出、删除明文文件、缺少密码时拒绝运行)。没有登录真实账号导出,也没有做真实导入恢复。

注意:计划和价格以 Bitwarden 官方价格页为准。不要共享个人账号或主密码,团队共享请用组织和集合。只导入、导出你自己有权管理的凭据。

安全提示:备份文件即使加密,也等于你整个保险库。备份密码要和主密码不同,单独记在纸上或另一个安全位置;不要把备份放在公开网盘的共享文件夹里。

做完之后你会得到什么?

成果 说明
bw_backup.sh 同步 → 导出 → 校验 → 轮转
加密备份 受密码保护,可导入任意 Bitwarden 账号
测试 不需要真实账号
恢复演练步骤 每季度做一次

需要准备哪些环境?

项目 要求 说明
Bitwarden CLI npm install -g @bitwarden/cli,本文用 2026.10.0 也可下载官方独立程序
Python 3 校验 JSON 系统自带即可
存放位置 本地加密磁盘或离线 U 盘 至少一份离线

文件结构

24-bitwarden-B-src/
├── bw_backup.sh
└── tests/
    ├── fakebin/bw          # 测试用的假 bw
    └── test_backup.sh

第 1 步:两种加密导出的区别

类型 能导入到哪里 风险
账号限定(不带 --password) 只能导回原账号 轮换账号加密密钥后旧备份无法解密
密码保护(带 --password) 任意 Bitwarden 账号 备份密码丢了就无法解密

做灾难恢复备份选密码保护。

第 2 步:备份脚本

bw_backup.sh:

#!/usr/bin/env bash
# Bitwarden 保险库加密备份:导出为“受密码保护”的 encrypted_json,保留最近 N 份。
# 需要:已登录的 bw CLI;环境变量 BW_SESSION(bw unlock --raw 得到)和 BACKUP_PASSWORD(备份文件密码)
set -euo pipefail
umask 077

BACKUP_DIR="${BACKUP_DIR:-$HOME/bw-backups}"
KEEP="${KEEP:-12}"
: "${BW_SESSION:?请先 export BW_SESSION=\$(bw unlock --raw)}"
: "${BACKUP_PASSWORD:?请设置 BACKUP_PASSWORD(与 Bitwarden 主密码不同,单独保存)}"

mkdir -p "$BACKUP_DIR"
bw sync >/dev/null
out="$BACKUP_DIR/bitwarden_$(date +%Y%m%d_%H%M%S).json"
bw export --format encrypted_json --password "$BACKUP_PASSWORD" --output "$out" >/dev/null

# 校验:必须是 JSON 且 encrypted 为 true、passwordProtected 为 true,否则删除并报错
if ! python3 - "$out" <<'PY'
import json, sys
d = json.load(open(sys.argv[1], encoding="utf-8"))
sys.exit(0 if d.get("encrypted") is True and d.get("passwordProtected") is True else 1)
PY
then
  rm -f "$out"; echo "✗ 导出文件不是受密码保护的加密格式,已删除" >&2; exit 1
fi

# 只保留最近 KEEP 份
ls -1t "$BACKUP_DIR"/bitwarden_*.json | tail -n +"$((KEEP + 1))" | xargs -r rm -f
echo "✓ 备份完成:$out(共保留 $(ls -1 "$BACKUP_DIR"/bitwarden_*.json | wc -l) 份)"

要点:

  • umask 077 让新文件默认只有自己可读写。
  • 校验 encrypted 和 passwordProtected,防止参数写错导出成明文。
  • 附件是否包含在导出中,以官方“导出保险库数据”说明为准;重要附件另外保存。

第 3 步:测试

tests/fakebin/bw:

#!/usr/bin/env bash
# 测试用的假 bw:模拟 sync 和 export
case "$1" in
  sync) echo "Syncing complete." ;;
  export)
    while [ $# -gt 0 ]; do [ "$1" = "--output" ] && out="$2"; shift; done
    if [ "${FAKE_PLAIN:-0}" = 1 ]; then echo '{"encrypted":false,"items":[]}' > "$out"
    else echo '{"encrypted":true,"passwordProtected":true,"salt":"x","kdfType":0,"kdfIterations":600000,"encKeyValidation_DO_NOT_EDIT":"x","data":"x"}' > "$out"; fi ;;
esac

tests/test_backup.sh:

#!/usr/bin/env bash
set -u
cd "$(dirname "$0")/.."
export PATH="$PWD/tests/fakebin:$PATH" BW_SESSION=fake BACKUP_PASSWORD=test-only
export BACKUP_DIR="$(mktemp -d)" KEEP=3
fail=0
for i in 1 2 3 4 5; do ./bw_backup.sh >/dev/null || fail=1; sleep 1; done
n=$(ls "$BACKUP_DIR" | wc -l); [ "$n" -eq 3 ] && echo "ok 保留 3 份" || { echo "FAIL 份数 $n"; fail=1; }
perm=$(stat -c %a "$(ls -1t "$BACKUP_DIR"/*.json | head -1)"); [ "$perm" = 600 ] && echo "ok 权限 600" || { echo "FAIL 权限 $perm"; fail=1; }
FAKE_PLAIN=1 ./bw_backup.sh 2>/dev/null && { echo "FAIL 明文未拦截"; fail=1; } || echo "ok 拦截未加密导出"
[ "$(ls "$BACKUP_DIR" | wc -l)" -eq 3 ] && echo "ok 明文文件已删除" || fail=1
unset BACKUP_PASSWORD; ./bw_backup.sh 2>&1 | grep -q BACKUP_PASSWORD && echo "ok 缺少密码时拒绝运行" || fail=1
rm -rf "$BACKUP_DIR"; exit $fail
bash tests/test_backup.sh

检查结果(本机实际输出):

ok 保留 3 份
ok 权限 600
ok 拦截未加密导出
ok 明文文件已删除
ok 缺少密码时拒绝运行

第 4 步:真实运行(本文未执行)

bw login                                   # 首次
export BW_SESSION=$(bw unlock --raw)
read -rs BACKUP_PASSWORD && export BACKUP_PASSWORD
./bw_backup.sh
bw lock

read -rs 不回显、不进入 shell 历史。--password 参数在运行期间会出现在进程列表里,多人共用的机器上不要运行这个脚本。

预期结果:✓ 备份完成:~/bw-backups/bitwarden_YYYYMMDD_HHMMSS.json(共保留 N 份)。

第 5 步:恢复演练

  1. 注册一个测试用的 Bitwarden 账号(或使用空的测试组织)。
  2. 网页版 工具 → 导入数据,格式选 Bitwarden (json),选择备份文件,输入备份密码。
  3. 抽查几个条目的用户名、网址、TOTP。
  4. 演练完删除测试账号中的数据。

调试示例

未解锁就运行,本机实际输出:

./bw_backup.sh: line 9: BW_SESSION: 请先 export BW_SESSION=$(bw unlock --raw)

: "${VAR:?提示}" 在变量缺失时立即退出并打印提示,避免脚本跑到一半才失败。

出错了怎么办?

现象 原因 解决
You are not logged in. 没有 bw login 先登录
Vault is locked. BW_SESSION 过期 重新 bw unlock --raw
导入时提示密码错误 备份密码记错 只能用正确密码;所以要演练
份数没有减少 KEEP 设置太大 调整 KEEP
自建服务器 CLI 默认连官方云 bw config server https://你的服务器

模板规则

  • 只做密码保护的加密导出,脚本校验格式。
  • 备份密码与主密码不同,离线保存。
  • 每季度做一次恢复演练。

项目资源

用途 地址
导出保险库数据 https://bitwarden.com/help/export-your-data/
加密导出 https://bitwarden.com/help/encrypted-export/
Bitwarden CLI https://bitwarden.com/help/cli/
导入数据 https://bitwarden.com/help/import-data/
Bitwarden 服务条款 https://bitwarden.com/terms/

备份的价值只在恢复时体现。脚本保证每次导出都是加密的、份数可控,恢复演练保证这些文件真的能用。