Vaultwarden 安全加固指南

Vaultwarden 1.37.4 安全加固指南:argon2 管理员口令、HTTPS 强制与真实客户端 IP、关闭注册与邀请、加密备份、fail2ban 联动与上线前检查清单,全部基于 Ubuntu 22.04 实测。

VaultwardenVaultwarden2026/10/17

Vaultwarden 安全加固指南

‍‍​​‌​> 目标:读完本文后,你可以把一台默认配置的 Vaultwarden 加固到可公网暴露的水平:管理员口令哈希化、全链路 HTTPS、注册与邀请收敛、加密备份、暴力破解防护(fail2ban 联动),并用文末清单逐项核验。

一、环境信息

本文加固动作均在下表环境实测执行,涉及的服务为直连部署形态(反向代理链路同样适用)。

项目实测值
操作系统Ubuntu 22.04.4 LTS(内核 6.8.0-138-generic)
Vaultwarden 版本1.37.4(Web Vault 2026.7.0)
数据库SQLite 3.53.2(诊断页实测)
数据目录/opt/data/vaultwarden(db.sqlite3 实测 290816 字节)
服务端口监听 80,对外 8222(直连验证);HTTPS 链路见第四章
fail2ban0.11.2(Ubuntu 22.04 官方仓库)
opensslOpenSSL 3.0.2(Ubuntu 22.04 自带)
管理台/admin,会话 Cookie VW_ADMIN(有效期实测 1200 秒)

加固前的基线事实:默认 SIGNUPS_ALLOWED=true(任何人可注册)、INVITATIONS_ALLOWED=true、ADMIN_TOKEN 未设置时管理台处于关闭状态(设置后才打开)、直连 HTTP 明文。以下章节逐项收敛这些暴露面。

二、攻击面与加固基线

Vaultwarden 公网部署需要面对四类攻击面,对应的加固基线如下表:

攻击面风险加固动作对应章节
管理台 /admin管理员口令暴力破解、明文口令泄露argon2 哈希化 + 限流 + 不对公网开放第三章
传输链路令牌与页面明文窃听全链路 HTTPS + 真实 IP 传递第四章
注册接口陌生人注册、垃圾账户关闭注册/域白名单/邀请收敛第五章
数据落地服务器失陷后备份数据库备份加密 + 异地保存第六章
认证接口主密码在线爆破fail2ban 联动日志封禁第七章

一个原则贯穿全文:Vaultwarden 的用户数据本身是端到端加密的(《Vaultwarden 介绍与选型指南》第三章),加固重点是保护「账户身份入口」与「服务端可用性」,避免攻击者获得可在线爆破主密码的立足点。

三、管理员口令 argon2 化

3.1 生成 PHC 字符串

ADMIN_TOKEN 支持明文口令或 argon2id 哈希两种形态。生产必须用哈希形态:文件里只有单向哈希,口令只在人脑中。Ubuntu 22.04 安装官方 argon2 工具并生成(完整参数见部署指南 2.2 节):

# apt-get install -y argon2
# echo -n "q1w2e3r4" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4
$argon2id$v=19$m=65540,t=3,p=4$NXJIcE1kMURMRGZ3OTBYZDgrdlRSWFIwWXVsNElFdlU3V0ZtakZuWUF4ST0$jXhsLhviXX2rEyQmARrfcXrT3H75bs+0D0EPbqgVBnM

参数组 -k 65540 -t 3 -p 4(64 MiB 内存、3 轮、4 并行)是官方 wiki 推荐值,单次校验耗时约几十毫秒,足以对抗离线爆破又不影响登录体验。把输出整串(含 $argon2id$ 前缀)写入 ADMIN_TOKEN,登录时用明文口令。

官方还提供 /vaultwarden hash 交互式工具;实测它在无终端环境下会直接 panic(完整回显见部署指南 2.2 节),无法交互时一律用 argon2 命令行。

3.2 登录验证与限流实测

正确口令登录成功(HTTP 200 + 会话 Cookie):

# curl -s -i -c /tmp/vw_cookies.txt -X POST http://127.0.0.1:8222/admin \
    -H "Content-Type: application/x-www-form-urlencoded" --data-urlencode 'token=q1w2e3r4' | head -1
HTTP/1.1 200 OK

错误口令返回 401,页面错误文案实测为 Invalid admin token, please try again.。管理台登录自带限流:实测连续错误尝试,前 2 次返回 401,第 3 次起返回 429:

attempt 1 -> 401
attempt 2 -> 401
attempt 3 -> 429
# curl -s -i -X POST http://127.0.0.1:8222/admin \
    -H "Content-Type: application/x-www-form-urlencoded" --data-urlencode 'token=wrong-token' | head -1
HTTP/1.1 429 Too Many Requests
Too many requests, try again later.

限流默认参数为窗口 300 秒、突发额度 3 次(ADMIN_RATELIMIT_SECONDS/ADMIN_RATELIMIT_MAX_BURST),限流状态保存在内存中,等待窗口结束或重启服务即恢复。

3.3 管理台暴露面收敛

即使口令已哈希化,/admin 仍应尽量不暴露公网:

  • 反向代理层对 /admin 路径加 IP 白名单或 VPN 网段限制;
  • 最保守做法:设 DISABLE_ADMIN_TOKEN=true 直接禁用管理台,配置全部走部署形态的环境变量(日常改配置需要重启服务,换来的是少一个公网入口);
  • 管理台会话有效期默认 1200 秒,会话 Cookie 仅作用于 /admin 路径且 HttpOnly(实测),不额外放大风险。

四、HTTPS 强制与真实客户端 IP

4.1 TLS 终结

Vaultwarden 的数据在客户端加密,但认证令牌与会话是明文 HTTP 载荷,必须全链路 HTTPS。生产统一在反向代理终结 TLS,nginx 参考配置(实测验证通过,完整部署与验证回显见部署指南第五章):

server {
    listen 443 ssl;
    server_name vault.example.com;
    ssl_certificate     /etc/nginx/ssl/vw.crt;
    ssl_certificate_key /etc/nginx/ssl/vw.key;
    ssl_protocols       TLSv1.2 TLSv1.3;
    client_max_body_size 525M;
    location / {
        proxy_pass http://127.0.0.1:8222;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_http_version 1.1;
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

实测验证链路(自签证书场景用 -k 跳过校验):

# curl -sk https://127.0.0.1:8443/alive
"2026-10-17T08:23:54.292263Z"
# curl -sk -o /dev/null -w "https / -> %{http_code}\n" https://127.0.0.1:8443/
https / -> 200
# curl -sk -o /dev/null -w "https /admin -> %{http_code}\n" https://127.0.0.1:8443/admin
https /admin -> 200

同时把服务端 DOMAIN 设为反代对外的 https 地址(影响令牌签发与邮件链接,实测对照见《Vaultwarden 1.37.4 配置参数详解》第三章)。证书用 Let's Encrypt(certbot)签发,自签证书仅限内网。

4.2 真实客户端 IP

服务端默认从 X-Real-IP 头取真实客户端 IP(参数 IP_HEADER 默认值即 X-Real-IP,IP_HEADER_TRUSTED_PROXIES 默认 local)。反代未传递该头时,日志与限流记录到的都是代理地址——第五章的实测日志就是证据(直连时记录的来源为网关地址)。两个纪律:反代必须设置 X-Real-IP;IP_HEADER_TRUSTED_PROXIES 不要放开到任意来源,防止伪造头绕过限流与封禁。

验证方法:接入反代后从外部访问一次,查看服务日志中响应行的 IP 是否为客户端真实地址(日志行格式实测示例见第七章 7.2 节)。

4.3 端口收敛

公网防火墙只放行 443(或自定义 HTTPS 端口);Vaultwarden 原始端口(8222)只对内网/本机开放,管理台若未加白名单则同样只对内。可用 ufw 或云平台安全组实现,规则变更后用外部探测确认原始端口不可达。

五、关闭注册与邀请收敛

5.1 关闭开放注册

SIGNUPS_ALLOWED=false 是公网部署的第一加固项。实测两步注册流程第一步即被拒绝(完整回显见《Vaultwarden 1.37.4 配置参数详解》4.1 节):

{"message":"Registration not allowed or user already exists","validationErrors":{"":["Registration not allowed or user already exists"]},...}
HTTP 400
[2026-10-17 08:14:27.652][vaultwarden::api::identity][ERROR] Registration not allowed or user already exists
[2026-10-17 08:14:27.652][response][INFO] (register_verification_email) POST /identity/accounts/register/send-verification-email => 400 Bad Request

提示文案刻意合并「不允许注册」与「用户已存在」两种情形,无法据此探测账户存在性。首个管理员账户在关闭注册之前创建(顺序见部署指南 3.4 节)。

5.2 注册策略组合

按暴露程度选择组合:

场景配置组合
完全封闭(仅既有账户)SIGNUPS_ALLOWED=false
限定域名的有限开放SIGNUPS_ALLOWED=true + SIGNUPS_DOMAINS_WHITELIST=corp.example.com
需要邮箱真实性保证叠加 SIGNUPS_VERIFY_EMAIL=true(配好 SMTP)
禁止任何人自行建组织ORG_CREATION_USERS=<管理员邮箱>

5.3 邀请与组织收敛

  • INVITATIONS_ALLOWED=false:仅当成员完全由管理员在管理台手动创建时使用;否则保持 true 供邀请加入;
  • ORG_CREATION_USERS:限制谁能创建组织,避免普通用户随意建组织产生管理噪音;
  • 邀请有效期默认 120 小时(INVITATION_EXPIRATION_HOURS),过期自动失效;
  • 实测部署中 SIGNUPS_ALLOWED=false、INVITATIONS_ALLOWED=false 双关(见部署指南 compose.yml),新成员全部走管理台路径。

六、备份加密

6.1 为什么备份必须加密

数据库 db.sqlite3 存的是密文(用户数据零知识),但备份中还有 rsa_key.pem(JWT 签名密钥)与配置文件(可能含 SMTP 凭据),且未来 KDF 强度不足的旧账户数据可能被离线攻击。备份文件外发(网盘、对象存储、异地机房)必须先加密。

6.2 openssl 加密备份实测

用 openssl 对数据目录打包加密(AES-256-CBC + PBKDF2 10 万轮派生密钥):

# cd /opt/data/vaultwarden && tar -czf /tmp/vw_data.tar.gz db.sqlite3 attachments
# openssl enc -aes-256-cbc -pbkdf2 -iter 100000 -salt \
    -in /tmp/vw_data.tar.gz -out /tmp/vw_data.tar.gz.enc -pass pass:Backup@2026
# ls -la /tmp/vw_data.tar.gz /tmp/vw_data.tar.gz.enc
-rw-r--r-- 1 root root 21594 10月 17 16:19 /tmp/vw_data.tar.gz
-rw-r--r-- 1 root root 21616 10月 17 16:19 /tmp/vw_data.tar.gz.enc

还原演练(验证加密包可恢复且内容一致):

# openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 \
    -in /tmp/vw_data.tar.gz.enc -out /tmp/vw_data_restore.tar.gz -pass pass:Backup@2026
# tar -tzf /tmp/vw_data_restore.tar.gz
db.sqlite3
attachments/
attachments/f8afa06c-7aab-444f-92a2-573cc9fcf22b/
attachments/f8afa06c-7aab-444f-92a2-573cc9fcf22b/d01e9799f624569e784d
# sha256sum /tmp/vw_data.tar.gz /tmp/vw_data_restore.tar.gz
9a2a8f6ee3034adf79871adcc37f6a494d2e02bbba88f1e5e3cb0eb973ffe9cd  /tmp/vw_data.tar.gz
9a2a8f6ee3034adf79871adcc37f6a494d2e02bbba88f1e5e3cb0eb973ffe9cd  /tmp/vw_data_restore.tar.gz

两个哈希一致说明加密/解密往返无损。纪律:加密口令与数据分开保管(口令走线下/密码管理器,不与备份放同一位置);定期做还原演练,只备份不演练等于没有备份。运行中数据库的一致性备份方法见《Vaultwarden 运维手册》第三章。

七、fail2ban 联动

7.1 原理

主密码在线爆破发生在登录接口,失败时服务日志会输出明确的错误行(实测):

[2026-10-17 08:17:38.410][vaultwarden::api::identity][ERROR] Username or password is incorrect. Try again. IP: 172.17.0.1. Username: admin@vaultwarden.local.

对应的接口响应为 HTTP 400,{"message":"Username or password is incorrect. Try again",...}。fail2ban 轮询该日志,按来源 IP 统计失败次数并调用防火墙封禁。前提(第四章):反代传递真实 IP,日志中的 IP: 字段必须是客户端地址。

7.2 过滤器与验证

Ubuntu 22.04 安装 fail2ban:

# apt-get install -y fail2ban
# fail2ban-client --version
Fail2Ban v0.11.2

创建过滤器 /etc/fail2ban/filter.d/vaultwarden.conf:

[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <HOST>\. Username:.*$
            ^.*Invalid admin token, please try again\. IP: <HOST>.*$
            ^.*Sign-ups not allowed.*IP: <HOST>.*$
journalmatch = _SYSTEMD_UNIT=vaultwarden.service

服务日志通过 systemd 单元输出(StandardOutput=append:/var/log/vaultwarden.log 或 journald + journalmatch)。用实测日志行验证过滤器匹配(4 条真实失败日志样本):

# fail2ban-regex /tmp/vw_sample.log /etc/fail2ban/filter.d/vaultwarden.conf
...
|-  #) [# of hits] regular expression
|   1) [4] ^.*Username or password is incorrect\. Try again\. IP: <HOST>\. Username:.*$
`-
Ignoreregex: 0 total

Date template hits:
|- [# of hits] date format
|  [4] {^LN-BEG}ExYear(?P<_sep>[-/.])Month(?P=_sep)Day(?:T|  ?)24hour:Minute:Second(?:[.,]Microseconds)?(?:\s*Zone offset)?
`-

Lines: 4 lines, 0 ignored, 4 matched, 0 missed
[processed in 0.00 sec]

4 lines, 4 matched 表明时间戳解析与失败行提取全部命中,过滤器可直接投产。

7.3 监狱配置与运维命令

创建 /etc/fail2ban/jail.d/vaultwarden.local:

[vaultwarden]
enabled  = true
port     = 443,8222
filter   = vaultwarden
backend  = auto
logpath  = /var/log/vaultwarden.log
maxretry = 3
findtime = 300
bantime  = 3600

阈值参考服务端自带限流(登录限流默认 60 秒窗口/突发 10 次,管理台 300 秒/3 次):fail2ban 管跨请求的持续性爆破,maxretry=3、findtime=300 是与内置限流互补的常见起点。启用与巡检:

# systemctl enable --now fail2ban
# fail2ban-client status vaultwarden
# fail2ban-client set vaultwarden unbanip <IP>

上线前用错误口令连续触发几次,确认 status vaultwarden 中失败计数与封禁列表按预期增长(File filter 段的实测匹配已在上面验证)。

八、上线前加固检查清单

逐项核对(每项都附实测验证途径):

#检查项验证方法本文实测锚点
1管理口令为 argon2id PHC配置中 ADMIN_TOKEN 以 $argon2id$ 开头;明文口令能登录3.1/3.2 节实测
2管理台限流生效连续错 3 次出现 HTTP 4293.2 节实测
3全链路 HTTPScurl https://<域名>/alive 返回 200;诊断页 HTTPS 检查4.1 节实测
4真实客户端 IP 入日志外部访问后日志 IP: 为客户端地址4.2 节(直连对照 172.17.0.1)
5开放注册已关闭匿名注册返回 400 + Registration not allowed5.1 节实测
6KDF 轮数达标prelogin 返回 ≥100000(实测注册用户 600000)《Vaultwarden 1.37.4 配置参数详解》4.4 节
7附件配额已设置USER_ATTACHMENT_LIMIT/ORG_ATTACHMENT_LIMIT 非空第六章/配置参数详解
8备份加密可还原还原演练 sha256 一致6.2 节实测
9fail2ban 过滤器匹配fail2ban-regex 4/4 matched7.2 节实测
10原始端口不对公网外部探测 8222 不可达4.3 节

再叠加两个例行项:每次升级后重跑本清单;订阅安全公告(GitHub Releases),安全版本发布后尽快跟进(《Vaultwarden 运维手册》第四章升级流程)。

九、参考链接