vdi-cloud/docs/cloud-mfa-20261111.md

51 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 管理员双重验证(2026-11-11)
已部署本机 `http://127.0.0.1:5182`。入口为右上角锁形按钮「双重验证」,三个角色均可维护本人设置。既有账号默认不启用;root 密码和原登录方式保持,未为用户账号自动绑定验证器。
## 使用
1. 点击「双重验证」,输入当前密码开始绑定。在身份验证器中手动添加账号,填入页面显示的密钥,选择基于时间、6 位、30 秒更新;本期提供手动密钥,不生成二维码。
2. 输入动态码并点击「验证并开启」。绑定准备有效 10 分钟,必须在发起绑定的同一登录中确认;确认前不启用。关闭准备窗口不会启用验证,重新开始会生成新密钥。
3. 保存只显示一次的 8 条恢复码,可下载文本。每条只能使用一次;关闭窗口后无法再次查看原码。开启后其他登录立即失效,当前登录保留。
4. 登录先验证用户名和密码,启用账号随后出现动态码/恢复码输入框。验证成功前不签发或保存登录令牌。动态码成功使用一次后需等待身份验证器刷新,服务端容许前后一个 30 秒时间步的时钟误差。
5. 更新恢复码或关闭验证,均须当前密码及有效动态码/恢复码,并二次确认。更新使全部旧恢复码作废,关闭恢复密码登录;两项操作均撤销其他登录,保留当前登录。
动态码遵循 [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238),使用 SHA-1、6 位和 30 秒时间步。请保持验证器和服务器时间同步。丢失验证器和全部恢复码时需要受控运维恢复,当前网页不提供其他管理员代删 MFA、邮件找回或目录服务恢复;重置密码也不会绕过已有双重验证。
## 接口与保护
| 接口 | 用途 |
| --- | --- |
| `GET /api/v1/auth/mfa` | 本人启用状态、剩余恢复码数量,不回显密钥 |
| `POST /api/v1/auth/mfa/setup` | 当前密码验证后生成临时绑定密钥 |
| `POST /api/v1/auth/mfa/confirm` | 验证动态码、启用并返回一次性恢复码 |
| `POST /api/v1/auth/mfa/recovery` | 当前密码和验证代码校验后更新恢复码 |
| `DELETE /api/v1/auth/mfa` | 当前密码和验证代码校验后关闭 |
| `POST /api/v1/auth/login` | 新增可选 `code`;启用账号必须通过第二因素 |
- 临时和启用密钥使用 AES-GCM 加密,独立用途密钥由 `VDI_JWT_SECRET` 派生,附加认证数据绑定管理员标识。备份恢复须保留对应环境密钥,不能只恢复数据库或随意替换 JWT 密钥。
- 恢复码使用 128 位随机值,库中仅保存哈希;消费、会话创建、恢复码轮换、设置修改及相关审计使用事务。TOTP 时间步单调递增,同一动态码及同一恢复码的并发请求仅一次成功。
- 账号行锁将登录与权限/密码/MFA 修改串行,事务内复核当前登录及最新账号状态。开启、关闭及恢复码更新分别记录 `enable_mfa/disable_mfa/rotate_mfa_recovery`,审计不保存密钥、明文恢复码、密码或验证码。
- MFA 设置验证和登录各使用独立持久化尝试预算:每账号每 5 分钟 10 次、每来源地址 30 次。失败尝试和成功尝试均计数;返回 429 与 Retry-After。错误密码不会暴露账号是否已启用 MFA,也不会消费恢复码。
- 密钥、恢复码和密码只在当前页面流程中短暂保留,关闭窗口清理,不写入 localStorage/sessionStorage。恢复码仅通过明确下载操作保存到用户本地。
新增 `admin_mfa/admin_mfa_recovery` 附表,不改原账号及会话表字段。关闭 MFA 删除本人附表记录及恢复码;删除临时管理员时级联清理。验证设置取消或过期后不激活,过期密文保留至下一次绑定覆盖或账号清理。
## 验收
- 独立 PostgreSQL 的 Go 全量测试与 vet 通过;专项通过 RFC 六组 SHA-1 测试向量(含 2038 年之后)、时间窗口、动态码重复使用拒绝、恢复码重复使用拒绝、并发消费、密文账号绑定、三角色本人维护、准备过期/跨登录拒绝及尝试限制。另补充超级管理员重启后设置保留及改密仍需第二因素的验证,专项通过。
- 前端 lint/typecheck、3 项单元测试和生产构建通过;新增 6 项 MFA 页面测试通过,既有管理员/在线登录/界面 12 项回归通过。最初 3 条错误文案断言未包含请求编号,修正断言后全部通过,应用提示逻辑正常。
- 真实临时只读账号完成开启、原登录撤销、密码单独登录拒绝、真实当前时间动态码登录、动态码重复拒绝、恢复码登录及重复拒绝、恢复码更新及旧码失效、关闭后密码登录。设置变化审计不含秘密,临时账号及其 MFA/会话已清理。
- 真实浏览器操作完成绑定确认、恢复码下载、登录第二因素、恢复码登录及关闭;1440/390px 深浅主题通过,无脚本异常、非预期 API 错误或越界写请求。真实截图仅展示登录提示及启用状态,不保存有效密钥或恢复码。
- 原账号/密码指纹、用户授权、终端身份与配置、告警规则及三台 VM 配置摘要一致,盒子在线。验收期间盒子另行提交成功的 `gpu-prepare` 任务:业务任务 61→62,VM100 开机、VM101 关机,VM102 保持关机。该次设备任务和前后状态已完整保留,不把电源变化当作本轮 MFA 测试操作,也未强制恢复现场状态。
证据:[真实接口](evidence/cloud-mfa-20261111/live-verification.json)、[真实页面](evidence/cloud-mfa-20261111/browser-verification.json)。集成测试只使用一次性 `vdi-mfa-test-db`,未在业务库清空数据;隔离库为减少清理同步等待临时关闭 fsync,因此这些测试不证明数据库断电恢复能力,业务 PostgreSQL 配置未改动。
## 部署与回退
部署前备份 `.local/live/backups/before-mfa-20261111-154828.dump`,原镜像标签 `before-mfa-20261111-154828`。独立构建基线二进制与部署前 SHA-256 一致:`ac04d8f5423b07aa2afa442013a4ddeaee55bbf0343a0876c50a8e829c6a4779`,保留已部署 GPU 功能及 Compose 配置。
旧 API 不检查新增 MFA 表,直接回退会绕过第二因素。只要存在已启用 MFA 的账号,就必须保留强制验证的兼容 API,不能直接回退到旧镜像;部署脚本的失败恢复也加入了启用账号检查。只有确认没有启用账号且没有后续部署时,才可恢复原镜像并沿用 `.local/mfa-review/compose.release.yml` 和原环境配置;附表可保留,不删除业务卷或恢复整库覆盖其他工作。
此项为可选的本人 TOTP 与恢复码,尚未实现组织强制策略、目录集成、硬件安全密钥或 WebAuthn。专用 VM、Windows 副本、额外磁盘及真实快照还原仍按用户要求暂缓。