NodeJS使用Bcrypt做哈希对比时错误对比字符串仍返回true问题求助
问题排查结果
核心诱因
Bcrypt算法本身存在固定输入长度限制:仅对明文输入的前72个字节做哈希计算,超出部分会被直接丢弃。
你序列化后的userData对象JSON字符串结构为:
{"dateNow":"xxx","userId":xxx,"passwordHash":"xxx","email":"xxx"}
常规场景下,dateNow、userId、email三个字段拼接后的JSON内容总长度已经覆盖了前72个字节,passwordHash的内容完全落在72字节之外,所以修改passwordHash的值不会影响Bcrypt的哈希计算结果,对比自然永远返回true;而修改前三个字段的内容会改变前72字节的内容,对比就能正常返回false。
存在的其他隐藏问题
你的hashUserData函数递归调用时未添加await关键字,当生成的哈希命中/或.的过滤规则时,返回的是Promise对象而非字符串,会导致后续逻辑异常。
解决方案
1. 调整字段顺序保证核心字段落在有效计算区间
将passwordHash放到对象的最前面,确保它的内容在Bcrypt的72字节处理范围内,生成哈希和对比校验时的对象字段顺序必须完全一致:
// 生成哈希时的对象结构 const userData = { passwordHash: foundUser.rows[0].user_password, dateNow, userId: foundUser.rows[0].user_id, email: foundUser.rows[0].user_email }; // 对比校验时的对象结构也要保持相同字段顺序 const userDataToCheck = { passwordHash: foundUser.rows[0].user_password, dateNow: req.params.dateNow, userId, email: foundUser.rows[0].user_email };
2. 修复哈希生成函数的递归问题
const hashUserData = async (userData, saltRounds) => { let hashedData = await bcrypt.hash(JSON.stringify(userData), saltRounds); if (hashedData.includes('/') || hashedData.includes('.')) { // 补充await关键字,等待递归结果返回 hashedData = await hashUserData(userData, saltRounds); } console.log('hashUserData', hashedData) return hashedData; };
3. (推荐优化)替换URL安全处理逻辑
递归过滤/和.的方式效率极低,极端场景下会触发栈溢出,建议直接对生成的哈希做字符替换适配URL规则,无需重复生成哈希:
// 生成哈希后转为URL安全格式 const toUrlSafeHash = (rawHash) => { return rawHash.replace(/\+/g, '-').replace(/\//g, '_').replace(/\./g, '~'); }; // 对比前将URL中的安全哈希转回原始格式 const fromUrlSafeHash = (urlSafeHash) => { return urlSafeHash.replace(/-/g, '+').replace(/_/g, '/').replace(/~/g, '.'); };
内容的提问来源于stack exchange,提问作者Duncan
相关产品推荐
相关产品推荐

