# Smail 超级管理员重置与邮箱验证码需求文档 ## 1. 文档信息 | 项目 | 内容 | |---|---| | 文档名称 | Smail 超级管理员重置与邮箱验证码需求文档 | | 文档状态 | 产品决定与文档复审已通过,待实施 | | 当前版本 | 0.3 | | 编写日期 | 2026-08-25 | | 适用项目 | Smail | | 主要范围 | 独立超级管理员重置程序、部署端本机重置通道、外部邮箱绑定、登录邮箱二次验证、外部邮箱密码恢复和安全审计 | > 本文档用于确定管理员密码重置和邮箱验证码的完整产品边界。本文档已经完成产品确认,但不代表相关功能已经实现。 > 外部邮箱验证码已经纳入本轮正式开发范围,必须完成验证码服务、SMTP 投递、登录邮箱二次验证、外部邮箱密码恢复、外部邮箱管理页面、运营数据和定期清理;功能开关只用于安全验收后的受控启停,不得作为跳过实现的依据。 --- ## 2. 背景 Smail 已经确定以下账户安全基础: 1. 系统采用超级管理员、管理员和普通用户三级角色; 2. 管理员和普通用户允许通过用户名或完整用户邮箱登录; 3. 密码统一使用经过评审的 Argon2id 方案,不保留旧弱算法回退; 4. 管理员和普通用户可以使用离线恢复码和 WebAuthn 安全密钥建立恢复能力; 5. 超级管理员可以不配置离线恢复码; 6. 超级管理员不能通过普通 Web 修改密码或使用公开“忘记密码”流程; 7. 超级管理员只能由部署人员在部署主机上通过受保护的本机通道重置; 8. 外部安全邮箱验证码已经确认完整发送、绑定、登录、恢复、管理和运营数据清理流程,并纳入本轮正式开发。 为避免超级管理员重置入口暴露到网络,同时为管理员和普通用户提供可控的邮箱验证与恢复能力,需要单独确定管理员重置程序和验证码系统的需求。 --- ## 3. 建设目标 ### 3.1 核心目标 1. 单独构建 `smail-admin` 超级管理员重置程序,并在安装 Smail 时同步安装; 2. 将 Smail 主服务生命周期管理与超级管理员密码重置明确分离; 3. 超级管理员重置程序不得通过 HTTP、HTTPS 或 TCP 暴露; 4. Linux 使用 Unix Domain Socket,Windows 使用 Named Pipe 建立受保护的本机重置通道; 5. `smail-admin` 不直接读取数据库凭据、配置主密钥或修改数据库; 6. 所有密码修改继续调用 Smail 主程序内的统一密码策略、密码哈希和凭据撤销服务; 7. 建立统一邮箱验证码服务,为外部邮箱绑定、邮箱变更、登录二次验证和密码恢复提供能力; 8. 邮箱验证码只能发送到已经验证或正在验证的外部邮箱,不发送到用户当前无法登录的 Smail 邮箱; 9. 邮箱验证码不得被当作 WebAuthn 等级的强认证,不得单独批准高风险系统操作; 10. 建立验证码限流、防枚举、单次消费、仅内存生命周期管理和完整审计能力; 11. 明确超级管理员、管理员和普通用户在密码恢复与验证码使用上的权限差异; 12. 保证 Windows 开发环境和 Ubuntu 22.04、Ubuntu 24.04 生产环境具备一致的安全边界。 ### 3.2 非目标 本需求不包含以下能力: 1. 不修改或扩展 systemctl 的标准命令集合; 2. 不实现 `systemctl reset-admin smail` 等自定义 systemctl 动词; 3. 不允许通过 Web 页面重置超级管理员密码; 4. 不允许通过公网、局域网或 localhost TCP 开启超级管理员重置通道; 5. 不实现仅凭邮箱验证码免密登录; 6. 不把邮箱验证码标记为与 WebAuthn 等价的强认证因素; 7. 不允许验证码单独批准数据库迁移、配置回滚、角色变更等高风险操作; 8. 不通过命令行参数、环境变量、URL 或 systemd unit 名称传递新密码; 9. 不允许 `smail-admin` 绕过统一密码服务直接更新用户表; 10. 不在本需求中增加 TOTP、短信验证码或第三方社交账号登录。 --- ## 4. 术语定义 | 术语 | 定义 | |---|---| | Smail 主程序 | 提供邮件、Web、认证、数据库和插件能力的 `smail` 服务程序 | | Smail 管理程序 | 单独构建和安装的 `smail-admin` 本机安全管理程序 | | 部署端重置 | 部署人员在 Smail 所在主机上使用系统管理员权限执行的超级管理员密码重置 | | 本机控制通道 | Linux Unix Domain Socket、Windows Named Pipe 或等效受保护本机 IPC | | 重置通道 | 为一次超级管理员密码重置临时建立的短时、一次性安全会话 | | 外部邮箱 | 用户在 Smail 账户安全设置中绑定的非当前 Smail 登录邮箱 | | 邮箱验证码 | 通过外部邮箱发送、绑定用户和用途、短时有效且只能消费一次的数字验证码 | | 验证任务 | 仅存在于签发验证码的 Smail 认证进程内存中的一次验证码生成、发送、校验和消费过程 | | 密码重置授权 | 验证恢复方式成功后签发的短时、一次性密码修改授权 | | 近期重新认证 | 用户在限定时间内重新验证当前密码或 WebAuthn 后获得的高风险操作授权 | | 强恢复凭据 | WebAuthn 安全密钥或离线恢复码,不包括单独的邮箱验证码 | --- ## 5. 角色和权限边界 ### 5.1 超级管理员 超级管理员允许: - 使用外部邮箱接收安全通知; - 配置全局验证码发送策略和 SMTP Relay 引用; - 查看验证码系统的脱敏运行状态、发送统计和审计记录; - 通过 Web 管理端重置管理员和普通用户密码; - 在部署主机上使用 `smail-admin` 重置自己的超级管理员密码。 - 允许绑定外部邮箱接收通知 超级管理员禁止: - 通过 Web 修改或找回自己的密码; - 通过外部邮箱验证码重置自己的密码; - 通过普通 HTTP API 开启部署端重置通道; - 查看任何用户的验证码、完整外部邮箱、恢复码或 WebAuthn 私密信息; - 为其他用户直接设置一个未经目标邮箱验证的外部邮箱; - 使用邮箱验证码代替高风险操作的近期重新认证或 WebAuthn 二次确认。 ### 5.2 管理员 管理员允许: - 绑定和管理自己的外部邮箱; - 为自己的账户启用登录邮箱二次验证; - 使用符合角色策略的恢复方式重置自己的密码; - 在具备独立重置能力、完成近期重新认证或 WebAuthn 二次确认后,重置普通用户密码; - 查看自己的验证码发送记录和安全通知状态。 管理员禁止: - 修改全局验证码和 SMTP Relay 配置; - 查看或修改其他用户的外部邮箱和验证码状态; - 重置其他管理员或超级管理员的密码; - 仅凭邮箱验证码执行高风险管理操作; - 通过邮箱验证码获得超级管理员能力。 ### 5.3 普通用户 普通用户允许: - 绑定和管理自己的外部邮箱; - 为自己的账户启用登录邮箱二次验证; - 使用已经验证的外部邮箱验证码恢复自己的密码; - 查看自己的外部邮箱脱敏信息、验证状态和最近安全通知。 普通用户只能操作自己的验证码和外部邮箱,不能访问其他用户或全局验证码配置。 --- ## 6. 程序和安装要求 ### 6.1 构建产物 Smail 必须生成两个相互独立的程序: ```text smail smail-admin ``` 推荐源码入口: ```text backend/cmd/smail/main.go backend/cmd/smail-admin/main.go ``` Windows 构建产物为: ```text smail.exe smail-admin.exe ``` ### 6.2 Linux 安装布局 ```text /smail 放在统一的安装目录下,便于管理 ``` `smail-admin` 禁止设置 setuid,禁止赋予普通用户执行权限。 ### 6.3 安装和升级 Smail 安装程序必须: 1. 同时安装 `smail` 和 `smail-admin`; 2. 将 `smail` 注册为 systemd 或 Windows Service; 3. 不把 `smail-admin` 注册为常驻网络服务; 4. 不覆盖已有配置、数据和主密钥; 5. 不自动开启超级管理员重置通道; 6. 检查两个程序的版本和发布标识一致; 7. 升级时原子替换两个程序; 8. 任一程序安装失败时不得留下版本不一致的半完成状态; 9. Windows 使用 ACL 限制 `smail-admin.exe` 仅允许 Administrators 和 SYSTEM 执行; 10. Linux 使用文件权限和运行时身份双重限制管理程序。 11. `smail-admin` 必须作为短时一次性服务随 Smail 安装;正式执行入口固定为 `systemctl start smail-admin`,不得把它设计为常驻网络服务。 --- ## 7. 服务管理和重置入口 主程序生命周期继续使用标准命令: ```bash systemctl start smail systemctl stop smail systemctl restart smail systemctl status smail ``` 超级管理员重置使用: ```bash systemctl start smail-admin ``` 不采用以下形式: ```bash systemctl reset-admin smail systemctl start smail admin systemctl start admin ``` 允许通过受保护的本机凭据交互设置密码,但输入时不得回显明文。普通 systemd 服务不继承调用终端,因此 Linux 必须使用 `systemd-ask-password` 或等效的短时受保护本机交互;无可用密码代理或安全交互环境时必须安全拒绝。 --- ## 8. 超级管理员部署端重置 ### 8.1 固定命令 Linux 正式执行入口固定为: ```bash systemctl start smail-admin systemctl stop smail-admin ``` `smail-admin` 不允许开机自启动,安装、升级和系统预设均不得为其建立 `enable`、`WantedBy`、`RequiredBy` 或其他启动依赖。`start` 是唯一允许进入超级管理员重置流程的启动动作,`stop` 只允许终止正在执行的短时重置事务;`restart`、`try-restart`、`reload`、`reload-or-restart`、自动重启和依赖拉起均不得开启或重新进入重置流程。 `status`、`show`、`is-active`、`journalctl` 等只读查询不属于重置入口,可以用于部署诊断,但不得创建重置会话、获取密码或调用本机重置通道。本机 `root` 可以修改 systemd 单元和程序文件,因此安全边界以“阻止普通用户、服务账户、网络请求、插件和非预期 systemd 动作触发”为目标,不宣称能够阻止已经完全控制部署主机的 `root`。 允许增加只读辅助命令: ```bash smail-admin version smail-admin doctor ``` 禁止提供通过参数传递密码的选项。 `smail-admin` 是执行一次重置事务后退出的短时 systemd 服务。密码不得通过命令行参数、环境变量、临时明文文件、日志或标准输出传递;Windows 使用等价的服务启动语义和 Named Pipe,但不得降低身份校验、凭据交互和审计要求。 ### 8.2 启动检查 执行重置前必须检查: 1. Linux 当前有效 UID 为 `0`,或 Windows 当前进程具有本机管理员权限; 2. 主程序和管理程序版本兼容; 3. Smail 已完成最低限度初始化; 4. 目标账户存在且角色为 `super_admin`; 5. 本机控制通道权限和所有者正确; 6. 当前不存在另一个正在进行的超级管理员重置会话; 7. 当前平台具备已经通过安全测试的 IPC 适配器。 任何检查失败都必须拒绝继续,不允许降级为直接修改数据库。 ### 8.3 本机 IPC Linux 推荐地址: ```text /run/smail/admin-control.sock ``` Windows 推荐地址: ```text \\.\pipe\smail-admin-control ``` 安全要求: 1. Linux 使用 Unix Domain Socket,Windows 使用 Named Pipe; 2. 不监听 TCP,不注册到普通 HTTP Router; 3. 不允许反向代理、插件或前端访问; 4. Linux 服务端必须验证对端进程凭据和 UID; 5. Windows 服务端必须验证客户端令牌和管理员身份; 6. 文件权限或 ACL 不能代替服务端身份验证; 7. 控制协议只接受固定消息类型和严格长度限制; 8. IPC 地址和凭据不得由普通配置接口修改。 ### 8.4 重置会话 状态固定为: ```text closed → open → consumed ↘ expired ``` 要求: 1. 每次只创建一个重置会话; 2. 会话绑定目标超级管理员、用途、主进程实例和管理程序实例; 3. 默认有效期不超过 5 分钟; 4. 只能消费一次,消费前必须原子标记已使用; 5. 达到失败阈值、管理程序退出、主程序重启或通道断开后立即失效; 6. 终态不得恢复为 `open`; 7. 服务端只保存维护凭据的不可逆校验值; 8. 会话不得跨进程、跨用户、跨环境或跨主机复用。 ### 8.5 密码输入 `smail-admin` 必须通过终端无回显输入两次新密码。 禁止通过以下位置传递密码: - 命令行参数; - 环境变量; - URL; - 配置文件; - systemd unit 名称; - 标准输出; - 日志和审计详情。 密码必须调用主程序统一密码策略和统一 Argon2id 哈希服务。 ### 8.6 数据修改边界 `smail-admin` 只负责检查部署权限、连接本机 IPC、进行终端交互和显示脱敏结果。 `smail-admin` 禁止: - 读取数据库密码和配置主密钥; - 自行构造数据库 DSN; - 直接更新用户表; - 自行实现另一套密码哈希; - 调用普通 HTTP 管理接口; - 加载插件或启动邮件服务。 密码更新必须由 Smail 主程序在数据库事务中完成。 ### 8.7 重置后的处理 重置成功后必须: 1. 更新密码哈希和密码更新时间; 2. 递增 Session、Security 和 Credential 版本; 3. 撤销全部登录 Session; 4. 撤销全部 WebAuthn 凭据; 5. 撤销已有离线恢复码; 6. 撤销未完成恢复流程和未消费票据; 7. 清除受信任设备和长期登录状态; 8. 标记下次登录必须重新检查和配置安全凭据; 9. 向已验证外部邮箱发送安全通知; 10. 写入部署端安全审计; 11. 立即销毁本次重置会话。 --- ## 9. 分角色强制重置管理员和普通用户 密码重置权限矩阵固定如下: | 操作者 | 可以重置的目标 | |---|---| | 超级管理员 | 管理员、普通用户 | | 管理员 | 普通用户 | | 普通用户 | 仅自己,且只能使用本人修改密码或忘记密码流程 | | 部署端 `smail-admin` | 超级管理员自身 | 超级管理员可以通过管理后台重置管理员和普通用户密码,但不能通过该入口重置自己。管理员可以通过独立授权入口重置普通用户,但不能重置管理员或超级管理员。 要求: 1. 必须验证操作者对应的跨用户重置能力和目标角色范围; 2. 必须具备近期重新认证或 WebAuthn 二次确认; 3. 明确显示目标用户名、主邮箱和角色; 4. 禁止任何 Web 入口重置超级管理员;管理员还必须被禁止重置管理员; 5. 临时密码使用密码学安全随机源,只显示一次; 6. 设置 `must_change_password=true`; 7. 撤销目标用户全部 Session、WebAuthn、离线恢复码、恢复流程和重置票据; 8. 递增 Session、Security 和 Credential 版本; 9. 目标用户下次登录必须修改密码并重新生成离线恢复码; 10. 目标用户必须收到重新绑定 WebAuthn 的提示; 11. 向目标用户已验证外部邮箱发送通知; 12. 通知失败不得回滚已经完成的密码和凭据撤销事务; 13. 操作者、目标用户、操作者角色、授权能力、撤销范围和结果必须写入安全审计; 14. 管理员重置普通用户时必须复用与超级管理员跨用户重置相同的事务、凭据撤销和通知边界,不得建立弱化实现。 --- ## 10. 邮箱验证码用途 统一验证码服务支持: | 用途 | 标识 | 首版状态 | |---|---|---| | 绑定外部邮箱 | `external_email_bind` | 实现 | | 更换外部邮箱 | `external_email_change` | 实现 | | 登录邮箱二次验证 | `login_step_up` | 实现 | | 外部邮箱密码恢复 | `password_recovery` | 实现 | | 高风险操作验证 | `sensitive_operation` | 禁止启用,仅保留扩展标识 | 验证码必须绑定用户 ID、用途、目标邮箱、验证任务 ID、过期时间、凭据版本和请求上下文。不同用途、用户和邮箱之间不得复用。 --- ## 11. 外部邮箱绑定 ### 11.1 数量和用途 每个用户最多绑定: ```text 一个主要外部邮箱 一个备用外部邮箱 ``` 管理员和普通用户可以将已验证外部邮箱用于登录二次验证和密码恢复。超级管理员的外部邮箱只用于安全通知。 ### 11.2 绑定流程 ```text 正常登录 → 近期重新认证 → 输入外部邮箱 → 发送绑定验证码 → 验证成功 → 保存绑定 ``` 要求: 1. 用户只能管理自己的外部邮箱; 2. 外部邮箱规范化后保存; 3. 外部邮箱不能与当前用户的 Smail 主邮箱相同; 4. 未验证邮箱不能用于登录、恢复和安全通知; 5. 超级管理员不能替用户设置未经验证的邮箱; 6. 验证失败不得保存部分绑定状态; 7. 绑定成功后向新邮箱发送通知; 8. 操作写入安全审计。 ### 11.3 更换和删除 更换外部邮箱必须完成近期重新认证并验证新邮箱。新邮箱验证成功后原子替换旧邮箱,并向旧邮箱发送变更通知。 更换或删除后必须使以下数据失效: - 发往旧邮箱的未完成验证码; - 依赖旧邮箱的未完成密码恢复流程; - 旧邮箱对应的登录二次验证事务。 --- ## 12. 登录邮箱二次验证 ### 12.1 登录流程 ```text 用户名或完整用户邮箱 + 密码 ↓ 统一密码认证成功 ↓ 判断邮箱二次验证策略 ↓ 向已验证外部邮箱发送验证码 ↓ 验证码验证成功 ↓ 创建完整登录 Session ``` 验证码只作为密码后的第二步,不支持验证码免密登录。密码正确但验证码未通过时,不得创建完整 Session。 ### 12.2 策略 首版支持: ```text off 关闭 always 每次登录 new_device 新设备登录 ``` 用户可以提高自己的验证强度,但不能绕过超级管理员设置的全局强制策略。首版不依赖复杂 IP 地理判断。 ### 12.3 发送目标和失败处理 登录验证码只能发送到已验证的外部邮箱,不能发送到: - 用户正在尝试登录的 Smail 邮箱; - 未验证邮箱; - 请求临时提供的邮箱; - 管理人员临时指定的邮箱; - 插件提供的邮箱。 密码错误时不得发送验证码。重新发送后旧验证码失效。投递失败不得绕过验证直接登录,用户可以改用已经配置的 WebAuthn。 --- ## 13. 外部邮箱密码恢复 ### 13.1 公共入口 启用公开自助重置功能并配置有效 Web 域名或访问 IP 后,固定入口为 `https://域名/Reset` 或 `https://IP/Reset`。`/Reset` 大小写敏感,只允许 `GET` 加载页面;功能关闭、系统未进入 `ready` 状态或未配置有效访问主机时返回不可用。页面和全部恢复 API 必须使用同一后端开关,不能只隐藏前端入口。 该入口只允许管理员和普通用户进入自助恢复流程。超级管理员访问时不得创建验证码、WebAuthn 恢复会话或重置票据,仍只能使用部署端 `systemctl start smail-admin` 和受保护本机 IPC。 忘记密码页面允许输入用户名或完整用户邮箱,并始终返回: ```text 如果该账号存在并已配置可用的恢复方式,我们将发送恢复信息。 ``` 不得返回账号是否存在、角色、是否绑定外部邮箱和实际发送结果。 ### 13.2 普通用户 普通用户允许使用以下任意路径: ```text 路径 A:密保问答 + 离线恢复码 路径 B:WebAuthn 安全密钥 路径 C:已验证外部邮箱验证码 路径 D:由管理员执行重置 路径 E:由超级管理员执行重置 ``` 邮箱验证码验证成功后签发短时、一次性密码重置授权,再允许设置新密码。 ### 13.3 管理员 管理员允许使用: ```text 路径 A:WebAuthn 安全密钥 路径 B:密保问答 + 离线恢复码 路径 C:外部邮箱验证码 + 离线恢复码 路径 D:由超级管理员执行重置 ``` 管理员不能仅凭外部邮箱验证码完成密码重置。 ### 13.4 超级管理员 超级管理员不进入公开忘记密码流程,无论是否绑定外部邮箱都不能创建可用恢复任务。唯一恢复入口为: ```bash systemctl start smail-admin ``` ### 13.5 密码重置授权 密码重置授权必须: 1. 使用密码学安全随机源; 2. 服务端只保存不可逆校验值; 3. 绑定用户 ID、恢复路径、用途和凭据版本; 4. 默认有效期不超过 5 分钟; 5. 只能使用一次,使用前原子标记已消费; 6. 用户名、邮箱或凭据版本变化后立即失效; 7. 密码重置成功后撤销同一用户全部未完成恢复流程; 8. 不进入日志、浏览器持久化存储和审计详情。 ### 13.6 用户自行恢复后的处理 管理员或普通用户自行恢复密码后: 1. 更新密码并递增 Session 版本; 2. 撤销全部旧 Session 和未完成重置票据; 3. 保留现有 WebAuthn 凭据; 4. 保留现有有效离线恢复码; 5. 向主要和备用外部邮箱发送通知; 6. 下次登录显示安全检查提示; 7. 允许用户主动撤销 WebAuthn、重新生成恢复码和退出全部设备。 保留强恢复凭据是为了避免外部邮箱被攻击者控制后,攻击者通过邮箱恢复同时移除用户已有的 WebAuthn 和离线恢复码。 --- ## 14. 验证码规则 ### 14.1 默认参数 | 参数 | 默认值 | |---|---:| | 格式 | 8 位数字 | | 有效期 | 10 分钟 | | 最大错误次数 | 5 次 | | 重新发送间隔 | 60 秒 | | 单账号每小时发送上限 | 5 次 | | 单账号每天发送上限 | 10 次 | | 单 IP 每小时发送上限 | 20 次 | | 同用户同用途有效任务 | 1 个 | | 验证成功后的使用次数 | 1 次 | | 密码重置授权有效期 | 5 分钟 | 超级管理员可以在受限范围内调整发送上限和有效期,但不能关闭防暴力破解、单次消费和用途绑定。 ### 14.2 生成和消费 1. 验证码使用操作系统密码学安全随机源生成; 2. 禁止使用时间戳、递增序列和普通伪随机数; 3. 验证任务 ID 至少使用 128 位随机值; 4. 同一用户同一用途只保留最新验证码; 5. 重新发送、验证成功、达到错误次数或过期后立即失效; 6. 并发提交最多一次成功; 7. 验证码不能跨用户、用途、邮箱和环境使用; 8. 验证码任务只能保存在签发验证码的 Smail 认证进程内存中; 9. Smail 服务停止、重启、崩溃、升级或实例切换后,全部未完成验证码立即失效; 10. 重新发送验证码时,必须原子删除同一用户同一用途的旧内存任务; 11. 内存验证码任务必须设置全局容量上限,达到上限时安全拒绝新任务; 12. 过期验证码任务必须由统一清理器及时删除,不得为每个任务无限创建独立线程或 goroutine。 --- ## 15. 数据保护 ### 15.1 验证码内存生命周期 验证码及其校验数据不得写入数据库、配置文件、磁盘缓存、持久化缓存、消息队列、日志、审计详情、指标、链路追踪和备份。验证码验证任务只能保存在负责签发验证码的 Smail 认证进程本机内存中,首版不允许使用数据库、Redis、文件或其他外部组件保存验证码任务。 验证码明文只允许在以下阶段短暂存在: 1. 使用操作系统密码学安全随机源生成验证码; 2. 构建验证码邮件; 3. 将邮件交给 SMTP 投递组件; 4. 计算内存验证码校验值。 完成上述操作后,服务端必须尽最大努力覆盖并释放验证码明文缓冲区。业务代码不得继续保留或访问验证码明文,内存验证任务只能保存验证码的 HMAC 校验值。 内存验证任务至少包含: ```text challenge_id user_id purpose target_email_fingerprint code_verifier expires_at attempt_count send_count credential_version request_context_hash created_at ``` `code_verifier` 使用当前 Smail 进程启动时生成的临时随机密钥,通过 HMAC-SHA-256 计算,并绑定验证任务 ID、用户 ID、用途、目标邮箱指纹和验证码。 进程临时密钥必须满足: 1. 使用操作系统密码学安全随机源生成; 2. 长度不得低于 256 位; 3. 不得写入数据库、文件、配置、环境变量和日志; 4. 不得通过管理接口、插件接口和诊断接口读取; 5. Smail 服务停止或重启后立即失效; 6. 每次进程启动必须重新生成。 验证码任务在验证成功、过期、达到错误次数、重新发送、恢复流程结束、目标邮箱变化、凭据版本变化或服务退出后必须立即从内存删除。验证码验证和删除必须作为原子操作执行,并发请求最多只能有一个请求验证成功。 Smail 服务停止、崩溃、升级或重启后,所有未完成验证码任务立即失效,用户必须重新获取验证码。系统不得从数据库或其他持久化介质恢复验证码任务,也不得因为任务丢失而绕过验证。 首版验证码服务按照单认证实例设计。未来启用多个认证实例前,必须实现由服务端保护的验证码任务归属路由,确保验证请求返回签发实例;签发实例退出后验证码直接失效,不得通过持久化验证码任务实现跨实例恢复。 ### 15.2 非敏感运营数据和定期清理 数据库可以保存不包含验证码、验证码校验值和验证秘密的限流、投递、统计和脱敏审计数据,包括: - 账号小时和每日发送次数; - IP、规范化登录标识和邮箱指纹限流计数; - 最近发送时间; - SMTP 投递成功或失败结果; - 验证成功或失败结果; - 验证用途、操作用户 ID 和脱敏外部邮箱摘要; - 安全告警、用户可见最近发送记录和每日聚合统计。 数据库、文件、缓存、消息队列、日志、审计详情、指标、链路追踪和备份禁止保存: ```text code code_ciphertext code_digest code_verifier otp_runtime_key email_body ``` 持久化审计需要关联发送、验证和恢复流程时,应另外生成不具备验证码验证能力的 `audit_correlation_id`,不得持久化内存验证任务使用的 `challenge_id`。 后台数据清理任务必须每 14 天执行一次,推荐保留策略为: | 数据类型 | 保留时间或删除条件 | |---|---| | 小时限流计数 | 限流窗口结束后立即失效,在下一次清理任务中删除 | | 每日限流计数 | 限流窗口结束后立即失效,在下一次清理任务中删除 | | IP、登录标识和邮箱指纹限流数据 | 30 天 | | SMTP 详细投递结果 | 30 天 | | 用户最近验证码发送记录 | 30 天 | | 验证失败详细记录 | 完成安全审计汇总后保留 30 天 | | 每日脱敏聚合统计 | 90 天 | | 验证码安全审计和超级管理员重置审计 | 至少 365 天 | | 设置安全调查保留标记的数据 | 调查结束前禁止自动清理 | 达到保留期限的数据不再参与业务判断,并在达到期限后的第一次 14 天周期清理任务中物理删除。清理任务失败时继续保持逻辑失效状态,不得因为旧记录仍存在而延长验证码、恢复授权或限流窗口。 清理任务必须满足: 1. 首次安装后默认启用,每 14 天执行一次; 2. 服务启动时检查是否错过执行时间,错过时补执行一次; 3. 清理失败后每 6 小时重试并向超级管理员告警; 4. 同一环境同一时间只允许一个清理任务运行,多实例使用数据库租约或主节点选举避免重复执行; 5. 每批最多删除 1000 条,避免长事务和长时间锁表; 6. 不得删除仍在活动限流窗口或带有安全调查保留标记的数据; 7. 清理任务不得读取、导出或接触内存验证码任务; 8. 清理结果只记录任务 ID、时间、实例、数据类型、截止时间、删除数量、结果和脱敏失败分类; 9. 清理失败不得影响登录、邮件投递和验证码内存任务; 10. MySQL、PostgreSQL 和 SQLite 必须使用各自安全的空间复用或增量回收机制,不得每 14 天自动执行阻塞式全表压缩。 ### 15.3 外部邮箱存储 外部邮箱至少保存: ```text email_ciphertext email_fingerprint verified_at status type credential_version ``` 要求: 1. 完整邮箱使用随机 nonce 的认证加密; 2. 邮箱指纹使用独立索引密钥计算 HMAC; 3. API 默认只返回脱敏邮箱; 4. 完整邮箱只在发送时短时解密; 5. 完整邮箱不得进入普通日志和审计详情; 6. 密文篡改时拒绝解密和发送; 7. 主密钥不能与密文存放在同一数据库。 --- ## 16. SMTP Relay 和验证码配置 验证码系统复用统一 SMTP Relay 投递能力,但验证码策略单独配置。验证码配置通过 `transportProfileId` 引用 SMTP Relay,不重复保存 SMTP 密码。 建议配置范围: - 是否启用; - SMTP Relay 配置引用; - 发件人名称和发件地址; - 验证码长度、有效期和错误次数; - 发送间隔和频率上限; - 登录二次验证策略; - 管理员和普通用户恢复策略; - 测试邮件和投递告警。 启用前必须完成 SMTP Relay 验证、测试邮件、凭据加密、限流检查和审计检查。 SMTP 投递失败时: 1. 公共恢复接口仍返回统一提示; 2. 内部记录脱敏失败原因和告警; 3. 登录策略要求验证码时不得绕过; 4. 可以改用已配置的 WebAuthn 或离线恢复路径; 5. 不得降级为密保答案单独验证。 --- ## 17. API 边界 推荐用户接口: ```text GET /api/account/security/external-emails POST /api/account/security/external-emails/challenges POST /api/account/security/external-emails/verify DELETE /api/account/security/external-emails/{id} POST /api/auth/login/email-challenge POST /api/auth/login/email-verify POST /api/auth/password-recovery/start POST /api/auth/password-recovery/email/verify POST /api/auth/password-recovery/complete ``` 推荐超级管理员接口: ```text GET /api/admin/security/verification/status GET /api/admin/security/verification/audits PUT /api/admin/security/verification/config POST /api/admin/security/verification/test-email POST /api/admin/users/{userId}/password-reset ``` 禁止注册以下普通 Web 接口: ```text POST /api/admin/super-admin/password-reset POST /api/admin/reset-channel/open POST /api/setup/reset-super-admin ``` 所有接口必须执行后端能力、对象归属、Session、CSRF、限流和稳定错误码校验。公共恢复接口必须防止账号枚举。 --- ## 18. 页面需求 ### 18.1 登录页面 登录页面支持密码验证、邮箱二次验证、验证码重发、过期提示和替代 WebAuthn 验证。页面只显示脱敏外部邮箱。 ### 18.2 忘记密码页面 根据账户实际可用能力提供: ```text WebAuthn 安全密钥 密保问答 + 离线恢复码 外部邮箱验证码 ``` 超级管理员不能看到可用的 Web 重置入口。后端对超级管理员也不能创建恢复任务。 ### 18.3 账户安全页面 用户可以管理主要和备用外部邮箱、查看验证状态、设置登录邮箱二次验证、查看最近发送时间,并进入离线恢复码和 WebAuthn 管理入口。 超级管理员页面只提供通知邮箱,不显示“通过邮箱找回超级管理员密码”。 ### 18.4 超级管理员验证码设置页面 超级管理员可以配置验证码开关、SMTP Relay 引用、发件人、限流、角色策略和测试邮件,并查看脱敏投递统计与审计。 页面不得显示 SMTP 密码、完整验证码、完整外部邮箱和完整恢复票据。 --- ## 19. 审计要求 超级管理员部署端重置审计至少记录: - 事件类型和目标超级管理员 ID; - 主程序和管理程序版本; - 平台和调用者系统身份摘要; - 通道创建时间和最终状态; - 重置结果和凭据撤销范围; - 通知结果和失败原因分类。 验证码审计至少记录用途、用户 ID、目标邮箱脱敏摘要、发送结果、验证结果、限流结果、消费状态、请求 IP 摘要和关联恢复事务 ID。 审计禁止记录密码、验证码、维护凭据、完整外部邮箱、恢复码和 WebAuthn 私密数据。 验证码安全审计和超级管理员重置审计至少保留 365 天。限流、投递详情、最近发送记录和脱敏聚合统计按照第 15.2 节的期限保留,由每 14 天执行一次的受控后台任务清理。普通 Web API 不提供删除审计和清理任务记录的接口。 --- ## 20. 安全要求 ### 20.1 默认拒绝 1. 验证码功能默认关闭; 2. 未配置 SMTP Relay 时不能启用; 3. 未验证邮箱不能用于登录和恢复; 4. 未知用途和未知角色必须拒绝; 5. 超级管理员进入普通恢复流程必须拒绝; 6. 本机 IPC 权限或身份验证异常必须拒绝; 7. 主程序和管理程序版本不兼容必须拒绝。 ### 20.2 防枚举和限流 登录和忘记密码使用统一错误提示。验证码限流同时覆盖来源 IP、规范化登录标识、用户 ID、邮箱指纹、用途和浏览器事务。 禁止通过用户名与邮箱交替、主要与备用邮箱交替、重复发送和切换恢复方式绕过限流。 ### 20.3 高风险操作 邮箱验证码不得单独批准: - 数据库名称迁移; - 配置回滚; - 角色变更; - 修改数据库、SMTP、SSL 和加密主密钥配置; - 导出敏感审计数据; - 重置其他用户密码; - 修改全局验证码策略; - 开启超级管理员本机重置通道。 以上操作继续使用近期重新认证、WebAuthn、能力授权、恢复保障检查和审计保护。 --- ## 21. 测试要求 ### 21.1 `smail-admin` 测试 - [ ] 非 root 或非本机管理员执行被拒绝; - [ ] 主程序和管理程序版本不兼容被拒绝; - [ ] 密码不能通过参数和环境变量传入; - [ ] 本机通道不可用时安全失败; - [ ] 目标不是超级管理员时被拒绝; - [ ] 重置会话过期、退出和重启后失效; - [ ] 重置会话并发消费最多一次成功; - [ ] 审计和日志不包含密码及维护凭据。 ### 21.2 平台测试 - [ ] Ubuntu 22.04 和 Ubuntu 24.04 Unix Domain Socket 权限与对端 UID 验证; - [ ] Windows Named Pipe ACL 与客户端令牌验证; - [ ] TCP 扫描确认不存在重置端口; - [ ] 普通 HTTP Router 中不存在重置接口; - [ ] 插件和普通 `smail` 用户不能调用部署端重置能力。 ### 21.3 验证码测试 - [ ] 使用密码学安全随机源; - [ ] 验证码明文只在生成和 SMTP 投递阶段短暂存在; - [ ] 任何持久化介质均不保存验证码明文、密文、摘要、HMAC 校验值或进程临时密钥; - [ ] 验证码任务只存在于签发验证码的 Smail 认证进程内存; - [ ] 验证码绑定用户、用途和邮箱; - [ ] 过期、错误次数、重发失效和单次消费正确; - [ ] 并发验证最多一次成功; - [ ] 服务停止、崩溃、升级或重启后全部未完成验证码失效; - [ ] 服务重启不会清除持久化限流计数; - [ ] 内存任务达到容量上限时安全拒绝,不发生无限内存增长; - [ ] 后台任务每 14 天执行一次并按数据类型清理过期记录; - [ ] 清理失败能够重试和告警,且不影响登录和邮件服务; - [ ] MySQL、PostgreSQL 和 SQLite 均通过分批清理测试; - [ ] 邮箱密文篡改被拒绝; - [ ] 完整邮箱和验证码不进入日志。 ### 21.4 登录和恢复测试 - [ ] 用户名和完整邮箱登录进入同一验证码策略; - [ ] 密码错误时不发送验证码; - [ ] 验证码未通过时不创建完整 Session; - [ ] 不同用途验证码不能混用; - [ ] 普通用户可以通过已验证外部邮箱恢复; - [ ] 管理员仅凭邮箱验证码不能恢复; - [ ] 超级管理员不能通过外部邮箱恢复; - [ ] 不存在账号和存在账号的公共响应一致; - [ ] SMTP 失败和功能关闭不会形成降级绕过; - [ ] 用户自行恢复后保留 WebAuthn 和离线恢复码; - [ ] 超级管理员强制重置后撤销目标用户全部安全凭据。 --- ## 22. 验收标准 ### 22.1 构建和安装 - [ ] `smail` 和 `smail-admin` 可以独立构建; - [ ] 安装和升级时同步安装两个程序; - [ ] 两个程序版本一致; - [ ] `smail-admin` 只有部署管理员可以执行; - [ ] 安装和升级不会自动开启重置通道。 ### 22.2 超级管理员重置 - [ ] 超级管理员不能通过普通 Web 修改或找回密码; - [ ] `systemctl start smail-admin` 可以在受支持平台启动一次短时、受控的重置事务; - [ ] `smail-admin` 没有开机自启动关系,安装和升级会清理历史 `enable` 状态; - [ ] `systemctl stop smail-admin` 只能终止事务,`restart`、`try-restart`、`reload`、依赖拉起和自动重启均不能进入重置流程; - [ ] `status`、`show`、`is-active` 等只读查询不会创建重置会话或调用重置通道; - [ ] Linux 使用 Unix Domain Socket,Windows 使用 Named Pipe; - [ ] 不存在 TCP 或 HTTP 重置入口; - [ ] `smail-admin` 不直接读取或修改数据库; - [ ] 新密码使用统一密码策略和 Argon2id; - [ ] 重置后旧 Session、WebAuthn、恢复码和票据全部撤销; - [ ] 重置会话短时、一次性且不能重放; - [ ] 日志和审计不泄露敏感数据。 ### 22.3 邮箱验证码 - [ ] 外部邮箱绑定和变更必须验证目标邮箱; - [ ] 登录验证码只作为密码后的第二步; - [ ] 验证码发送到已验证外部邮箱; - [ ] 验证码按用户、用途和邮箱严格绑定; - [ ] 验证码一次性、短时有效并具有统一限流; - [ ] 验证码任务和校验值只存在于签发验证码的认证进程内存; - [ ] 服务停止或重启后全部未完成验证码失效且不能恢复; - [ ] 非敏感运营数据每 14 天执行一次受控清理; - [ ] 验证码安全审计至少保留 365 天; - [ ] 普通用户可以按策略使用外部邮箱恢复; - [ ] 管理员仅凭外部邮箱验证码不能恢复; - [ ] 超级管理员不能使用邮箱验证码恢复; - [ ] 邮箱验证码不能单独批准高风险操作; - [ ] SMTP 失败、功能关闭或数据异常时不会降级绕过认证。 ### 22.4 阻塞条件 出现以下任一情况时不得验收: 1. 超级管理员存在公开 Web 密码恢复入口; 2. 超级管理员重置通道监听 TCP; 3. 普通 HTTP Router 可以开启本机重置通道; 4. `smail-admin` 可以直接修改数据库; 5. 密码可以通过命令行参数或环境变量传递; 6. 本机 IPC 未验证调用者系统身份; 7. Windows Named Pipe 或 Linux Unix Domain Socket 未完成; 8. 重置会话可以重复消费或跨进程复用; 9. 验证码明文、密文、摘要、HMAC 校验值或进程临时密钥进入任何持久化介质; 10. 验证码任务能够在服务重启后恢复,或通过数据库、文件和外部持久化缓存跨实例共享; 11. 验证码能够跨用户或跨用途使用; 12. 邮箱验证码能够重置超级管理员密码; 13. 管理员能够仅凭邮箱验证码恢复密码; 14. 功能关闭或 SMTP 失败时能够绕过验证; 15. 内存验证码任务没有容量上限、原子消费或过期清理; 16. 14 天定期清理、失败重试、三种数据库兼容测试或 365 天安全审计保留未完成; 17. 跨平台测试和日志泄露检查未通过。 --- ## 23. 推荐实施顺序 1. 确认角色验证码权限、管理员组合恢复、外部邮箱数量和凭据保留策略; 2. 回写配置系统重构需求、技术设计和任务清单; 3. 创建 `smail-admin` 和固定本机控制协议; 4. 实现 Linux Unix Domain Socket 和 Windows Named Pipe; 5. 实现短时一次性超级管理员重置会话; 6. 将 `smail-admin` 纳入构建、安装和升级; 7. 实现外部邮箱数据模型和统一验证码服务; 8. 接入 SMTP Relay、限流、绑定和变更流程; 9. 实现仅内存验证码任务、进程临时密钥、原子消费和容量保护; 10. 实现非敏感运营数据持久化和每 14 天执行一次的分批清理任务; 11. 实现登录二次验证和分角色密码恢复; 12. 完成前端、审计、安全测试和跨平台验收。 --- ## 24. 已确认产品决定 以下项目已经确认,正式实施必须遵守: - [x] 登录邮箱验证码只作为密码后的第二步,不提供验证码免密登录; - [x] 验证码只发送到已验证外部邮箱,不发送到用户自己的 Smail 邮箱; - [x] 超级管理员可以绑定通知邮箱,但不能通过邮箱验证码重置密码; - [x] 独立程序命名为 `smail-admin`,Linux 正式执行入口固定为 `systemctl start smail-admin`; - [x] `smail-admin` 随 `smail` 一起构建、安装和升级; - [x] 管理员恢复要求外部邮箱验证码和离线恢复码组合; - [x] 普通用户可以只使用已验证外部邮箱验证码恢复密码; - [x] 每个用户最多绑定一个主要外部邮箱和一个备用外部邮箱; - [x] 验证码默认使用八位数字、十分钟有效、最多错误五次; - [x] 验证码发送复用 SMTP Relay,但验证码策略独立配置; - [x] 验证码任务和校验值只保存在签发验证码的 Smail 认证进程内存,不进入任何持久化介质; - [x] 限流、投递结果、脱敏统计和安全审计允许持久化,后台清理任务每 14 天执行一次; - [x] 投递和限流详细数据通常保留 30 天、脱敏聚合统计保留 90 天、安全审计至少保留 365 天; - [x] 首版按照单认证实例实现,服务重启或签发实例退出后未完成验证码立即失效; - [x] 用户自行通过邮箱恢复时撤销全部 Session,但保留 WebAuthn 和离线恢复码; - [x] 超级管理员或管理员跨用户强制重置时撤销目标 Session、WebAuthn、离线恢复码和全部未完成恢复票据; - [x] 邮箱验证码不能单独用于数据库迁移、配置回滚、角色变更和其他高风险操作; - [x] 超级管理员重置程序、跨平台本机 IPC 和相关安全测试未完成前不得验收; - [x] 超级管理员能够重置管理员和普通用户,管理员能够重置普通用户,普通用户仅能重置本人; - [x] 完整邮箱验证码服务、SMTP 投递、登录二次验证、外部邮箱恢复、外部邮箱管理页面、运营数据和定期清理均属于本轮正式开发范围。 --- ## 25. 评审记录 | 日期 | 评审人 | 状态 | 说明 | |---|---|---|---| | 2026-08-25 | 待填写 | 草案 | 根据已确定的超级管理员部署端重置路径和验证码推荐方案生成独立需求文档 | | 2026-08-25 | 用户确认 | 草案更新 | 确认验证码任务仅存进程内存,非敏感运营数据允许持久化并每 14 天执行一次清理 | | 2026-08-25 | 项目负责人(对话确认) | 产品决定确认 | 确认完整邮箱验证码正式实施范围、`systemctl start smail-admin` 唯一 Linux 正式入口和三级角色密码重置矩阵 | | 2026-08-25 | 文档复审 | 通过 | 与配置需求、技术设计和两份实施清单完成范围、命令、权限及依赖一致性复审 |