secrets.token_urlsafe() 是生成密码重置令牌的唯一安全选择,因其基于操作系统熵源、不可预测;而 random 模块使用伪随机算法,可被预测导致账户沦陷;推荐使用 32 字节(约 43 字符、256 bit 熵),并务必绑定 user_id 和 expires_at 且验证后立即标记为已使用。

secrets.token_urlsafe() 是生成重置密码令牌的首选,别用 random 或 uuid4。
为什么不能用 random 模块?
因为 random 是伪随机数生成器,输出可预测,攻击者在知道种子或部分输出后能反推后续值。重置令牌一旦被猜出,账户就直接沦陷。
常见错误现象:random.choice() 拼接字符串、random.randint() 生成数字再转 base64 —— 这些都不满足密码学安全要求。
-
secrets使用操作系统提供的熵源(如/dev/urandom),不可预测 -
random默认用Mersenne Twister,设计目标是统计均匀性,不是防攻击 - Django、Flask-Security 等框架内部发密码重置链接时,也优先调用
secrets.token_urlsafe()
secrets.token_urlsafe() 的长度怎么选?
长度直接影响熵值和抗暴力破解能力。太短易爆破,太长增加存储和传输开销。
推荐 32 字节(即 secrets.token_urlsafe(32)),实际生成约 43 个 URL 安全字符(Base64Url 编码),提供 ~256 bit 熵 —— 足够对抗离线暴力尝试。
- 16 字节 → 约 22 字符 → ~128 bit 熵:勉强可用,但不建议用于高权限账户
- 24 字节 → 约 32 字符 → ~192 bit 熵:生产环境常见折中
- 传参是字节数,不是最终字符串长度;
secrets.token_urlsafe(32)返回的是 str,无需再编码
生成后要立刻绑定用户与过期时间
令牌本身没意义,必须关联到具体用户 ID 和有效期,否则就是一张裸票。
典型错误:只存 token 值,没存 user_id 和 expires_at;或用内存 dict 临时缓存,服务重启就失效/不一致。
- 数据库表至少包含字段:
token(唯一索引)、user_id、used(bool)、created_at、expires_at - 生成后立即写入 DB,并设
expires_at = datetime.now() + timedelta(hours=1) - 验证时必须同时检查:
token 存在、未被使用、未过期、对应用户有效
真正容易被忽略的不是怎么生成,而是怎么销毁 —— 成功重置后必须把该 token 标记为 used=True 或直接删除,且不能依赖前端“跳转后自动失效”这种假定。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











