认证与安全模型
SyncTV 把安全边界拆成几层:
- 用户认证:密码、OPAQUE、WebAuthn/passkey、TOTP、恢复码、邮箱验证码和 OAuth2。
- 用户 2FA:用户可选开启,必须拥有至少两种本地验证方式。
- 访问 token:登录完成后签发,用于 HTTP/gRPC 业务 API。
- management 控制面:CLI 使用的管理端点,独立于普通用户 token。
- Provider 上游访问:Provider 自己决定上游 header 和凭据,不由 proxy 猜测客户端 header。
- 集群内部认证:节点间 gRPC 使用
cluster.secret。
登录方式与 2FA
Section titled “登录方式与 2FA”| 登录方式 | 可作为第一因素 | 可作为第二因素 | 说明 |
|---|---|---|---|
| 密码/OPAQUE | 是 | 仅当服务端返回 MFA_METHOD_PASSWORD 时可用 |
OPAQUE 登录不等同于 password MFA verifier |
| WebAuthn/passkey | 是 | 是 | 需要启用 WebAuthn 配置并完成绑定 |
| TOTP 身份验证器 | 否 | 是 | 使用 SHA-1、6 位验证码和 30 秒周期;服务端必须配置 security.totp_encryption_key |
| TOTP 恢复码 | 否 | 是 | 每个恢复码只能使用一次;恢复码属于 TOTP 因素,不单独计为一种本地验证方式 |
| 邮箱验证码 | 是 | 是 | 依赖 SMTP 和验证码发送能力 |
| OAuth2 | 是 | 否 | OAuth2 不参与本地 2FA,但 2FA 用户可以直接用 OAuth2 登录 |
用户开启 2FA 前,系统会确认至少有两种可用的本地验证方式。开启后,使用本地单因素方式登录会进入 MFA 会话,客户端需要根据返回的剩余验证方式完成第二步。
Token 上下文
Section titled “Token 上下文”开启 2FA 后,系统不应该接受旧的单因素 refresh token 继续刷新会话。满足 2FA 或 OAuth2 登录路径后签发的 token 会带有可接受的认证上下文。
实际语义:
- 用户未开启 2FA:普通本地登录、MFA 后登录、OAuth2 登录签发的 token 都可按正常规则使用。
- 用户开启 2FA:本地登录必须完成第二因素;refresh token 必须来自 MFA 后或 OAuth2 上下文。
- 用户关闭 2FA:普通单因素和 MFA/OAuth2 上下文都可继续使用,直到 token 自身过期或被吊销。
MFA 会话
Section titled “MFA 会话”本地第一因素成功后,如果需要第二因素,服务端不会直接签发最终 token,而是创建一个短期 MFA 会话。
客户端需要:
- 完成第一因素登录请求。
- 如果响应要求 MFA,读取可用的剩余验证方式。
- 如果剩余方式包含邮箱验证码,直接调用发送验证码接口。
- 如果剩余方式包含
MFA_METHOD_TOTP,调用VerifyMfaTotp。 - 如果剩余方式包含
MFA_METHOD_RECOVERY_CODE,调用VerifyMfaRecoveryCode。 - 使用 MFA 会话 ID 和第二因素证明完成登录。
- 保存最终 access/refresh token。
失败的 password、TOTP 和恢复码验证会进入对应的暴力破解保护。TOTP 和恢复码共享用户级失败计数,并结合客户端 IP 执行限制。
TOTP 与恢复码
Section titled “TOTP 与恢复码”服务端生成 20 字节随机 TOTP secret,并通过 otpauth:// URI 返回给客户端。客户端使用该 URI 生成二维码,也可以显示响应中的 secret 供用户手动输入。绑定流程有 10 分钟期限;用户必须提交一个有效 TOTP 验证码,服务端才会确认凭据并返回恢复码。
服务端用 security.totp_encryption_key 加密 TOTP secret,并把用户 ID 放入密文上下文。验证码验证接受当前 30 秒时间步及相邻时间步。服务端记录最近使用的时间步,同一验证码不能在登录和敏感操作之间重复使用。生产主机应启用 NTP 或 chrony,避免时钟偏差超出验证窗口。
绑定完成后,服务端返回 10 个恢复码。服务端保存恢复码哈希并丢弃明文;客户端应要求用户保存这些恢复码。重新生成会使旧恢复码全部失效,成功验证一个恢复码后,服务端会删除该恢复码。
开始绑定、重新生成恢复码和删除 TOTP 都需要一次有效的敏感操作验证。删除 TOTP 会减少一种本地验证方式;如果删除后无法保留两种本地验证方式,用户必须先关闭 2FA。每个敏感操作验证 ID 只能使用一次。
用户偏好与安全设置
Section titled “用户偏好与安全设置”用户偏好用于用户级配置,其中 two_factor_enabled 是安全敏感字段。
约束:
- 开启 2FA 前必须有至少两种可用本地验证方式。
- TOTP 与它的恢复码共同计为一种本地验证方式。
- 删除 passkey、解绑邮箱或删除 TOTP 时,如果 2FA 已开启,操作后仍必须保留至少两种可用本地方式。
- 管理员修改用户偏好时必须遵守角色层级,普通 admin 不能越权修改 root 或同级高权限用户。
management gRPC 是 CLI 和运维命令使用的控制面。
生产规则:
- 优先使用 Unix socket。
- 如果使用 TCP,必须设置
management.auth_token。 - 不要把 management TCP 端点暴露到公网。
- 通过文件或 secret manager 注入 token。
management.enable_reflection生产默认关闭。
management token 不是普通用户 access token。它代表运维控制面权限,应按基础设施 secret 管理。
Provider 与代理安全
Section titled “Provider 与代理安全”Provider 负责决定上游请求 header。proxy 层只执行 Provider 给出的配置。
这意味着:
- 原始客户端
Range、Accept、User-Agent等 header 不会被 proxy 自动转发。 - 如果上游需要
Range,Provider 必须显式选择。 - 如果直连 URL 绑定了
User-Agent,Provider 返回给客户端的 header 应与服务端代理 header 保持一致。 - 客户端无法设置所需 header 时,应使用代理模式。
Provider 凭据配置见 媒体 Provider;客户端如何选择直连、代理和播放信息见 播放与代理。
- 安全与密钥: 配置 JWT、OPAQUE、Provider 凭据加密、密码复杂度、CORS 和可信代理。
- 邮件与 OAuth2: 配置邮箱验证码、SMTP 和运行时 OAuth2 provider 配置。
- WebAuthn: 配置 passkey 的 RP ID、origin、允许 origin 和 challenge 超时。
- 限流: 配置 HTTP、gRPC、聊天、WebSocket 和认证相关限流。