密码重置token必须用密码学安全方式生成并严格校验:php用bin2hex(random_bytes(32)),node.js用crypto.randombytes(32).tostring('hex'),python用secrets.token_urlsafe(32),.net用websecurity.generatepasswordresettoken;生成后须绑定用户、过期时间并存库,验证时需原子性update作废,防止并发重放。

密码重置报错,十有八九出在 token 生成或验证环节——不是生成方式不安全,就是前后端对不上。关键不是“有没有 token”,而是“这个 token 能不能被后端正确识别、校验、作废”。
Token 必须用密码学安全方式生成
别用 md5(time().rand())、uniqid() 或 Math.random(),这些可预测、易碰撞、无熵值,攻击者几秒就能批量猜中。
- PHP 7+:用
bin2hex(random_bytes(32))→ 得 64 位十六进制字符串 - Node.js:用
crypto.randomBytes(32).toString('hex') - Python:用
secrets.token_urlsafe(32)(推荐)或os.urandom(32).hex() - .NET(WebSecurity):直接调
WebSecurity.GeneratePasswordResetToken(userName, 60),expiration 单位是分钟,建议设为 60 而非默认 1440
生成后必须绑定用户 + 过期时间 + 存库校验
token 不是“生成即发送”,它必须立刻写入数据库,并关联 user_id、created_at、expires_at、used(布尔)、email(防换绑)等字段。
基于官方 GMGN API 的代币分析工具。通过合约地址查询代币在 SOL/BSC/Base 链上的准确市场数据、安全检测、KOL 分析、开发者分析和 AI 智能分析(叙事/筹码/老鼠仓/机器人)。支持自动识别链。
- 字段类型建议:VARCHAR(128),加唯一索引,避免重复插入
- 过期时间必须由服务端控制(如 MySQL 的
NOW() + INTERVAL 1 HOUR),不能只靠前端隐藏链接 - 发新 token 前,先
UPDATE ... SET used = true WHERE user_id = ? AND used = false失效旧 token,防止多链接并行生效
验证时必须原子性检查 + 即时作废
收到重置请求后,不能先 SELECT 再 UPDATE —— 并发下会出竞态,导致同一 token 成功重置两次密码。
- 推荐一条 SQL 原子执行:
UPDATE password_resets SET used = true WHERE token = ? AND expires_at > NOW() AND used = false - 检查
RowsAffected === 1,不是 1 就说明 token 已用、过期或不存在 - Laravel 等框架会自动哈希存储 token(如
hash_hmac('sha256', $token, app.key)),验证时重新计算比对,原始 token 永远不落库
Django / Symfony / Laravel 常见 token 错误点
框架自带逻辑看似省事,但错配生成器或提取方式就会报 “bad token” 或 “invalid token”。
- Django allauth:必须用
allauth.account.forms.default_token_generator,不能混用django.contrib.auth.tokens - Symfony:重置链接模板里必须写
{{ url('app_reset_password', {token: resetToken.getToken()}) }},漏掉.getToken()就传空字符串 - Laravel:token 存的是 hash_hmac 结果,验证时不能查明文,也不能用
Str::random()替代random_bytes()










