本文档详细描述了本系统的安全威胁模型及相应的防御机制,涵盖 Token 生命周期管理、加密存储及防攻击策略。
| 威胁类型 | 描述 | 防御机制 | 对应文档 |
|---|---|---|---|
| Replay Attack (重放攻击) | 攻击者截获 Auth Code 并在合法客户端之前或之后尝试兑换。 | Atomic Consume (原子消费) + One-Time Use Enforcement。 | Data Consistency |
| Credential Leakage (凭据泄露) | 数据库被拖库导致 Client Secret 泄露。 | SHA256 Salted Hash。数据库仅存 Hash 值,绝不存明文。 | Data Persistence |
| Token Theft (令牌窃取) | Access Token 被截获。 | Short-lived Token (1小时) + Refresh Token Rotation (轮转机制)。 | 本文档 |
| CSRF | 攻击者诱导用户进行非预期的授权。 | 强制校验 state 参数 (推荐客户端实现)。 | API Reference |
- 有效期: 1小时。
- 用途: 访问受保护资源(如
/userinfo)。 - 验证: 无状态(JWT)或有状态(DB 查询)。本项目采用 有状态 验证,支持即时撤销。
- 有效期: 30天。
- 用途: 在 Access Token 过期后换取新 Token。
- 安全机制: 轮转 (Rotation)
- 每次刷新时,不仅颁发新的 Access Token,也会 颁发新的 Refresh Token。
- 旧的 Refresh Token 立即失效。
- 检测机制: 如果检测到旧 Refresh Token 被再次使用,系统可视为 Token 泄露,并级联撤销该用户的所有关联 Token(TODO Feature)。
- 存储:
sha256(secret + salt) - 传输: 仅在 POST body 中通过 HTTPS 传输。
- 敏感信息(如 DB 密码、Redis 密码)建议通过 环境变量 注入,而非硬编码在
config.json中。 - 生产环境部署时,应确保配置文件权限严格限制。
- HTTPS: 生产环境 必须 启用 HTTPS/TLS,否则 OAuth2 毫无安全性可言。
- PKCE: 对于移动端/SPA 客户端,建议开启 PKCE (Proof Key for Code Exchange) 模式(本后端已在数据库预留字段支持,需升级 Plugin 逻辑启用)。
- IP 白名单: 对于高权限 Client,建议限制 Token 兑换的源 IP。
所有 Token(Access Token、Refresh Token)在数据库中 仅存储 SHA-256 哈希值,绝不存储明文。
- 存储格式:
SHA-256(token_value) - 验证流程: 客户端提交 Token → 服务端计算哈希 → 与数据库哈希比对
- 优势: 即使数据库泄露,攻击者无法还原出有效 Token
- 算法: PBKDF2-SHA256
- 迭代次数: 310,000 次(符合 OWASP 2023 推荐)
- Salt: 每用户独立随机 Salt(16 字节)
- 输出: 32 字节密钥
系统支持从旧版 SHA-256 单次哈希渐进式迁移到 PBKDF2:
- 用户登录时,系统检测密码哈希格式
- 若为旧格式(SHA-256),验证通过后自动升级为 PBKDF2
- 迁移对用户透明,无需重置密码
每个 Refresh Token 链共享一个 token_family 标识符:
- 首次颁发 RT 时生成唯一
token_familyID - 后续轮转的 RT 继承同一
token_family - 系统可追踪整个 Token 链的生命周期
当检测到已撤销的 Refresh Token 被再次使用时:
- 检测: 收到的 RT 在数据库中标记为已撤销
- 判定: 视为 Token 泄露(攻击者持有旧 RT)
- 响应: 级联撤销该
token_family下的 所有 Token - 结果: 合法用户和攻击者均需重新认证
用户 → 服务器: 使用 RT-1 刷新
服务器: 撤销 RT-1, 颁发 RT-2 (同 family)
攻击者 → 服务器: 使用 RT-1 刷新 (重用!)
服务器: 检测到 RT-1 已撤销 → 级联撤销 family 所有 Token
用户: 下次请求失败, 需重新登录
- 外部标识: 使用 UUID v4 作为
public_sub(公开主体标识符) - 内部标识: 数据库自增 ID 仅用于内部关联
- 防枚举: UUID 不可预测,攻击者无法通过递增 ID 枚举用户
- OIDC 兼容:
id_token中的subclaim 使用public_sub
| 方案 | 可枚举 | 信息泄露 | OIDC 兼容 |
|---|---|---|---|
| 自增 ID | ✗ 可预测 | 泄露用户数量 | ✓ |
| UUID public_sub | ✓ 不可预测 | 无信息泄露 | ✓ |