Skip to content

fix(security): 验证码用 random.choices 生成、刷新令牌轮换非原子 #200

Description

@xiaocheny214

问题描述

用户认证流程中存在两个安全缺陷。

1. 验证码使用非加密安全的 PRNG

文件: backend/packages/app/src/windup_app/server/user/service.py:86-87

def _generate_code() -> str:
    return "".join(random.choices(string.digits, k=6))

random.choices 使用 Mersenne Twister,不是密码学安全的随机数生成器。攻击者若能观察足够多的输出(或知道种子),可以预测后续验证码。

2. 刷新令牌轮换非原子

文件: backend/packages/app/src/windup_app/server/user/service.py:394-401

# 撤销旧 token
self.redis.delete(redis_key)          # ← 第一步

# 签发新 token
new_access = create_access_token(...)
new_refresh, new_jti = create_refresh_token(...)
self._store_refresh_token(new_jti, user_id)  # ← 第二步

两步之间存在竞态窗口:

  • 服务崩溃 → 旧 token 已删、新 token 未存 → 用户被踢出
  • 并发重试同一旧 token 可能在窗口内成功

建议修复

  1. 验证码: import secrets,使用 secrets.choice(string.digits)secrets.token_hex(3)
  2. 令牌轮换: 使用 Redis MULTI/EXEC 或 Lua 脚本原子执行"删除旧 token + 存储新 token"。

影响

  • 严重程度: High
  • 验证码可预测 → 账户接管
  • Token 轮换竞态 → 用户意外登出或 token 复用

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0优先级 P0(最高,先做)bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions