PassIt 安全加固指南

PassIt 1.25.0 系统化加固实测:零知识凭据模型、MFA/注册三道闸、TLS 全链路、暴露面收敛、审计日志、root 降权与补丁策略,全部行为以实例实测为据。

PassIt密码管理自托管安全2026/10/24

PassIt 安全加固指南

目标:给已按《PassIt 1.25.0 Docker Compose 部署指南》跑起来的 PassIt 实例做一遍系统化加固——从身份认证、传输加密、网络暴露面到日志、降权与补丁策略。所有行为依据均为 1.25.0 实例实测(实测日期 2026-10-24),加固前后可对照验证。

加固思路速览:PassIt 的服务端天生"无解密能力"(零知识),加固重点不在"防止服务端泄密文",而在三件事——把主密码与登录凭据的暴露面收到最小(认证与注册治理)、把明文传输与 HTTP 会话彻底消灭(TLS 全链路)、把服务进程与后台组件的攻击面压到最低(暴露面收敛与降权)。

一、环境信息

项目值
应用版本PassIt 1.25.0(2026-10-16 发布,含登录限流收紧等安全修复)
部署形态三件套编排(应用 + PostgreSQL 17 + Valkey 8),宿主端口 8128
实测日期2026-10-24
参考基线《PassIt 1.25.0 Docker Compose 部署指南》、《PassIt 1.25.0 配置参数详解》

二、身份认证与访问控制

2.1 先理解凭据模型(加固的出发点)

PassIt 的登录凭据链是"主密码 → 客户端 Argon2id 派生 → 派生哈希作为 BASIC 凭据 → 换取 12 周 Token"(django-rest-knox)。三个实测证据:

  1. 主密码永不出客户端:注册接口 POST /api/users/ 强制要求客户端生成加密材料,缺任一项直接 400——服务端在协议层面拿不到主密码;
  2. BASIC 凭据是派生哈希而非主密码:直连 API 用主密码明文做 BASIC 认证返回 401,必须先取 client_salt 自行派生;
  3. 数据库里的密码字段是服务端二次哈希(pbkdf2_sha256),加密私钥列也是密文——即使拖库也拿不到可登录的凭据原文。

含义:加固的抓手是派生哈希与 Token 的传输与时效,而不是服务端存储。

2.2 开启 MFA(TOTP 与 FIDO2)

1.25.0 内置 MFA 模块(django_rest_mfa),支持 TOTP 与 FIDO2/WebAuthn 两种因素,相关端点集中在 /api/mfa/(生成、验证、激活、停用)。开启路径:用户登录后在账号设置中添加第二因素;WebAuthn 前必须把 FIDO_SERVER_ID 设为用户实际访问的域名(如 passit.example.com),否则浏览器会以域名不匹配拒绝注册密钥。对小团队建议强制所有人启用 TOTP:这是本版本"无管理后台 UI"现实下最实际的全局策略(管理员逐个确认)。

2.3 登录限流与锁定

1.25.0 的安全修复批次包含"Tighten lockouts"(收紧登录失败锁定)与"Throttle email sending endpoints"(邮件端点限流)(来源:gitlab.com/passit/passit-backend 提交记录,2026-10-15/16,查询日期 2026-10-24)。升级到 1.25.0 本身就是一次登录暴力破解防护的加固;对外发布时建议在反代层再加一层速率限制(如 nginx limit_req),双保险。

2.4 注册治理:三道闸

闸门机制配置位置
注册白名单(运行时)REGISTRATION_WHITELIST,存数据库,/admin/ 即改即生效/admin/ → Constance
组织域白名单(环境变量)IS_PRIVATE_ORG_MODE + PRIVATE_ORG_MODE_DOMAIN_WHITELIST编排 environment
邮箱确认(强制)长码链接 + 6 位短码双通道,未确认账号受权限限制EMAIL_CONFIRMATION_HOST 必须配对

实测记录(2026-10-24):设 IS_PRIVATE_ORG_MODE=True、PRIVATE_ORG_MODE_DOMAIN_WHITELIST=b.com 后,非白名单域注册被拒(在用户名可用性检查阶段即拦截),白名单域正常通过。生产建议:个人实例至少配一道白名单,彻底关闭"陌生人注册"通道。

2.5 管理后台收敛

Django admin(/admin/)默认开启(实测 GET /admin/login/ 返回 200),可管理用户与运行时配置,属于高价值目标。加固选择:

  • 不需要时:ENABLE_DJANGO_ADMIN=False,直接关闭;
  • 需要时:保留默认 True,但在反代层对 /admin/ 路径加 IP 白名单或 VPN 内才可达。

三、传输加密(TLS)

3.1 应用层的两个开关

参数默认实测行为(2026-10-24)加固建议
SECURE_COOKIETrueCookie 带 Secure 标记,HTTP 下浏览器拒收(实测 set-cookie 头尾有 Secure)HTTPS 生产保持默认;HTTP 验证场景临时 False
SECURE_SSL_REDIRECTFalse置 True 后 HTTP 请求 301 跳 HTTPS(实测 location: https://...)TLS 就绪后置 True

加固顺序(防自锁):先配反代证书 → curl 验证 https 可达 → 开 SECURE_SSL_REDIRECT → 移除 SECURE_COOKIE=False。

3.2 反向代理层(nginx 参考)

server {
    listen 443 ssl http2;
    server_name passit.example.com;
    ssl_certificate     /etc/letsencrypt/live/passit.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/passit.example.com/privkey.pem;

    # HSTS:确认全站 HTTPS 稳定后再加
    add_header Strict-Transport-Security "max-age=31536000" always;

    location / {
        proxy_pass http://127.0.0.1:8128;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }
}

Let's Encrypt + certbot 自动续期即可(官方安装指南同样要求"SSL is required")。应用自身默认响应头已含 CSP、X-Frame-Options: DENY、X-Content-Type-Options: nosniff、Referrer-Policy: same-origin、Cross-Origin-Opener-Policy: same-origin(实测回显),反代层无需重复设置,仅需补 HSTS。

3.3 响应头现状(默认即达标项)

content-security-policy: connect-src 'self' data:; default-src 'self'; font-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'
x-frame-options: DENY
x-content-type-options: nosniff
referrer-policy: same-origin
cross-origin-opener-policy: same-origin

CSP 的 script-src 含 'unsafe-inline' 'unsafe-eval'(Angular 运行时需要),不是可一键收紧项,保持默认即可。

四、网络与防火墙

4.1 暴露面清单(实测)

组件监听是否应对外说明
web(8080)宿主 8128仅经反代 443应用与 API 唯一入口
db(5432)编排内网否实测未映射宿主端口
cache(6379)编排内网否实测未映射宿主端口
/api/_health/web 内是(可读)健康检查无鉴权,仅返回 ok,监控用

加固动作:

  1. db/cache 保持不映射宿主端口(本编排已如此),靠编排内网隔离;
  2. 宿主防火墙只放 443(反代)与必要管理口,8128 仅本机回环可用:
root@passit-server:/opt/passit# ufw default deny incoming
root@passit-server:/opt/passit# ufw allow 443/tcp
root@passit-server:/opt/passit# ufw allow 22/tcp
root@passit-server:/opt/passit# ufw enable
  1. 若 8128 仅供本机反代使用,把编排端口映射改为 127.0.0.1:8128:8080,彻底杜绝绕过反代直连。

4.2 密钥与口令治理

  • SECRET_KEY:openssl rand -hex 40 生成,进密钥管理(不进代码库、不进聊天记录);更换会使全部登录 Token 失效(实测数据无损);
  • 数据库口令:与 DATABASE_URL 同步修改,避免三件套之外任何组件持有;
  • 示例口令禁用:本系列文档为演示使用 q1w2e3r4,生产必须替换。

五、审计日志

5.1 日志面

应用日志走 stdout(granian + Django),级别由 DJANGO_LOG_LEVEL 控制(默认 INFO)。加固配置:

root@passit-server:/opt/passit# docker compose logs -f web --since 10m

关键审计点:注册(含被白名单拒绝的尝试)、登录失败与锁定、邮箱确认、MFA 变更、密码修改。这些事件均出现在应用日志中,建议接入集中日志(journald 持久化或 filebeat/loki 转发)并保留 90 天以上。

5.2 监控与健康检查

  • 存活:GET /api/_health/ 返回 ok(实测无鉴权 200,适合监控探针);
  • 可用:GET /api/ping/ 返回 {"ping":"pong"};
  • 深度:GET /api/username-available/<email>/ 可探测注册服务就绪度(注意这本身是信息泄露面,见 5.3)。

5.3 信息泄露的取舍

用户名可用性查询接口(/api/username-available/)与用户公钥查询(/api/user-public-auth/)是零知识登录流程的必需品,但也能被用来枚举注册邮箱。组织模式白名单(2.4)+ 反代层限流可显著提高枚举成本;对纯私人实例,可在反代层直接拒绝来自公网的这两个路径。

六、服务降权与最小权限

实测(2026-10-24):web 容器内进程以 root 运行(uid=0),镜像未声明 USER。web 服务无状态(所有持久化在 PostgreSQL/Valkey),降权不影响数据:

  web:
    user: "1000:1000"

降权后需验证应用可正常读写 /tmp(迁移任务输出)与监听 8080(非特权端口,无碍)。db/cache 镜像自身已有专用用户与降权处理,无需额外动作。宿主侧:pgdata 目录属主为 postgres 容器内 uid(999),不要用 root 全局目录权限"图省事",按容器内 uid 授权即可。

七、补丁与版本策略

  1. 订阅版本信号:GitLab 项目(passit/passit-frontend 的 Releases/Tags)与 Docker Hub stable 标签更新;PassIt 处于维护模式,新版本=安全修复批次,见版本即升;
  2. 升级流程(部署篇 4.5):备份 → docker compose pull web → up -d → docker compose run --rm web ./manage.py migrate → 验证 _health 与登录;
  3. 回滚预案:升级前备份 SQL 与镜像 tag 双留,跨版本回滚以恢复备份为主;
  4. 邮件链路也是攻击面:1.25.0 已收紧邮件端点限流,SMTP 凭据按密钥管理,禁用例口令。

八、常见问题

8.1 开了 SECURE_SSL_REDIRECT 后网站打不开

TLS 未就绪即开启跳转(HTTP 301 到不存在的 https)。先回退该变量恢复访问,配好证书后再开启(顺序见 3.1)。

8.2 用户登录后立即掉线

检查反代是否透传了 Host 头(proxy_set_header Host $host)——Host 不匹配会影响 Cookie 作用域;同时确认未在 HTTP 反代场景下错误地保持 SECURE_COOKIE=True(浏览器拒收)。

8.3 拖库风险有多大

数据库中秘密与加密私钥均为密文(实测验证),密码字段为二次哈希;但 Valkey 缓存与会话数据、SMTP 凭据、SECRET_KEY 属于敏感明文面,备份与日志同样需按机密对待——备份文件加密存储(如 age/gpg 加密后再离线保存)。

8.4 管理员忘了密码怎么办

经 /admin/ 由另一管理员重置,或以维护模式进入容器执行 Django 管理命令(changepassword);主密码参与客户端解密,重置后该用户原有加密数据需经备份码/新密钥流程处理——这正是零知识架构的代价:服务端永远无法"找回"你的密码,备份码(注册时返回的 user_backup_code)请离线保存。

九、参考链接

  1. 官方安全模型:https://passit.io/security-model/ (查询日期 2026-10-24)
  2. 1.25.0 安全修复提交记录:https://gitlab.com/passit/passit-backend/-/commits/master
  3. Knox Token 机制:https://github.com/James1345/django-rest-knox
  4. 本平台系列篇:《PassIt 1.25.0 介绍与选型指南》(零知识架构)、《PassIt 1.25.0 Docker Compose 部署指南》(编排基线)、《PassIt 1.25.0 配置参数详解》(安全参数全集)
  5. 本平台同类加固篇:《Passbolt 5.16.0 安全加固指南》