为何要对密码重置Token进行哈希处理?Express密码重置功能开发疑问
为什么存储密码重置Token前需要哈希处理
你当前的功能逻辑是完全可运行的,对Token做哈希存储属于低成本高收益的纵深安全防护措施,核心目的是规避数据库泄露带来的次生风险,具体原因如下:
- 规避数据库拖库风险:如果你的数据库被攻击者非法获取,明文存储的重置Token可以被直接用来在有效期内重置任意用户的密码,攻击者完全不需要获取用户邮箱的访问权限,就可以接管大量用户账号。而哈希后的Token是单向不可逆的,攻击者就算拿到哈希值也无法反推出可以用来提交校验的原始Token,完全阻断了这个攻击路径。
- 几乎无额外开发成本:哈希逻辑只需要加2行代码即可实现,完全不影响原有业务流程:生成原始明文Token后先发给用户邮箱,再把原始Token做哈希后存入数据库即可,校验时把用户提交的Token做同样的哈希运算,和数据库存储的哈希值比对即可完成校验,逻辑和密码的哈希存储/校验完全一致。
修改后的参考代码如下(同时修复了原代码中邮件发送失败后未保存用户字段修改的小问题):
const forgotPassword = async (req, res) => { try { const user = await User.findOne({ email: req.body.email }); if (!user) { throw Error("incorrect email"); } // 生成原始明文Token,用于发送给用户 const resetPasswordTokenPlain = crypto.randomBytes(20).toString("hex"); // 哈希后存入数据库,不存储明文 user.resetPasswordToken = crypto.createHash('sha256').update(resetPasswordTokenPlain).digest('hex'); user.resetPasswordTokenExpire = Date.now() + 10 * (60 * 1000); await user.save(); const message = ` <h1>You have requested a password reset</h1> <p>Here is your token : </p> <p>${resetPasswordTokenPlain}</p> `; try { await sendEmail({ to: user.email, subject: "Password reset request", text: message, }); res.status(200).json({ message: "Email sent" }); } catch (err) { user.resetPasswordToken = undefined; user.resetPasswordTokenExpire = undefined; await user.save(); res.status(500).json({ message: "Email could not be sent" }); } } catch (error) { console.log(error); const errorDetails = handleErrors(error); res.status(400).json(errorDetails); } };
内容的提问来源于stack exchange,提问作者anon
相关产品推荐
相关产品推荐

