← 返回博客
安全密码重置事务邮件开发者

密码重置邮件的安全实现

token 生成、哈希存储、过期策略、防滥用和单次使用的完整安全实现。

更新于 2026年10月12日
密码重置邮件的安全实现

密码重置邮件的安全实现

密码重置邮件是攻击者最常盯上的入口之一。实现不当,账号就被接管了。

Token 的生成和存储

重置 token 必须用密码学安全的随机数生成器,长度不低于 32 字节,用 URL-safe Base64 编码:

const crypto = require('crypto');
const token = crypto.randomBytes(32).toString('base64url');

存储时不要明文存 token,存它的哈希:

const hash = crypto.createHash('sha256').update(token).digest('hex');
await db.query(
  'INSERT INTO password_resets (user_id, token_hash, expires_at) VALUES ($1, $2, NOW() + INTERVAL '15 minutes')',
  [userId, hash]
);

发送邮件

await rovela.emails.send({
  from: 'security@yourdomain.com',
  to: user.email,
  subject: '重置你的密码',
  html: resetTemplate({ resetUrl: `https://yourdomain.com/reset-password?token=${token}` }),
  text: `点击链接重置密码(15 分钟内有效):https://yourdomain.com/reset-password?token=${token}`,
});

过期和单次使用

  • 15 分钟过期:超时作废,要求重新申请
  • 使用后立即删除:token 用过一次就从数据库删掉
  • 邮箱不存在时也要返回"已发送":不要让攻击者枚举账号
// 不管邮箱存不存在,都返回同样的响应
res.json({ message: '如果该邮箱已注册,你将收到重置邮件' });

防滥用

  • 同一邮箱 1 小时内最多允许申请 3 次
  • 记录请求日志,包含 IP
  • 重置成功后通知用户(发一封"你的密码已被修改"邮件)

链接格式

重置链接要用 HTTPS,token 放在查询参数里,不要放在 hash 里(hash 不会发到服务器)。链接格式:https://yourdomain.com/reset-password?token=<token>