REST API密码更新测试异常:相同密码哈希值每次不同
密码更新测试失败:相同密码生成不同哈希值导致匹配失败
我在实现REST API时遇到密码更新测试问题:即使输入相同密码,每次生成的哈希值都不一样,导致哈希匹配失败,每次运行测试都会得到新的哈希值。已经加了console.log排查,但没找到问题,相关代码如下:
user.js
const getUserById = async (userId) => { try { const user = await app.db('users').where({ id: userId }).first(); return user; } catch (error) { throw error; } }; const updatePasswordDashboard = async (data) => { try { const user = await getUserById(data.id); console.log('Stored Password:', user.password); console.log('Hashed Password from Request:', getPasswdHash(data.password)); console.log('Password Request:', data.password); if(getPasswdHash(data.password) === user.password){ if (data.newPassword === data.confirmNewPassword) { try { const newPassHash = getPasswdHash(data.newPassword); const updatedUser = await app.db('users') .returning(['password', 'first_name']) .where({ id: data.id }) .update({ password: newPassHash }); return updatedUser; } catch (error) { return error; } } else { throw new ValidationError('Palavras-passes nao coincidem!'); } } else{ throw new ValidationError('Palavra-passe errada!'); } } catch (error) { throw error; } };
users.js
router.put('/updatepassworddashboard/:id', async (req, res) => { try { console.log('Request received:', req.body); const result = await app.services.user.updatePasswordDashboard({ id: req.params.id, password: req.body.password, newPassword: req.body.newPassword, confirmNewPassword: req.body.confirmNewPassword, }); return res.status(200).json({ resultado: result[0], message: 'Palavra-passe alterada com sucesso' }); } catch (err) { console.log(err); return res.status(400).json({ error: err }); } });
users.test.js
test('Teste 12 - Atualizar palavra passe - dashboard', () => request(app).put(`${MAIN_ROUTE}/updatepassworddashboard/${user.id}`) .set('authorization', `bearer ${user.token}`) .send({ password: '12345', newPassword: '1234567', confirmNewPassword: '1234567',}) .then((res) => { expect(res.status).toBe(200); expect(res.body.password).not.toBe(''); }));
问题根源
密码哈希函数(比如bcrypt这类)每次生成哈希时会自动生成随机盐值,所以直接用===比较哈希字符串是完全错误的。不同的盐值会导致相同密码生成不同的哈希结果,这是哈希算法的安全设计,目的是防止彩虹表攻击。
修复步骤
- 替换哈希比较逻辑:不要直接调用
getPasswdHash(data.password)和存储的哈希做相等判断,改用哈希库提供的专门验证方法(比如bcrypt的bcrypt.compare())。修改后的代码示例:const updatePasswordDashboard = async (data) => { try { const user = await getUserById(data.id); console.log('Stored Password:', user.password); console.log('Password Request:', data.password); // 用哈希库的compare方法验证密码,而不是重新哈希后对比 const isPasswordValid = await bcrypt.compare(data.password, user.password); if(isPasswordValid) { if (data.newPassword === data.confirmNewPassword) { const newPassHash = await bcrypt.hash(data.newPassword, 10); // 10为盐轮数,可根据需求调整 const updatedUser = await app.db('users') .returning(['password', 'first_name']) .where({ id: data.id }) .update({ password: newPassHash }); return updatedUser; } else { throw new ValidationError('Palavras-passes nao coincidem!'); } } else { throw new ValidationError('Palavra-passe errada!'); } } catch (error) { throw error; } }; - 检查
getPasswdHash实现:如果这个函数是你自己封装的,确保它使用了带随机盐的哈希算法(比如bcrypt.hash()),而不是MD5、SHA这类无盐哈希。如果是第三方库,确认它的哈希逻辑是安全的。 - 统一哈希调用:不要在代码中多次调用哈希函数(你之前调用了两次
getPasswdHash(data.password)),既浪费性能,也可能因为盐值随机导致结果不一致,应该尽量减少不必要的哈希计算。 - 测试前置验证:确保测试用的用户初始密码是通过正确的哈希流程存入数据库的,比如在测试setup阶段用同样的哈希函数生成初始密码的哈希值,再插入数据库。
额外优化
- 去掉嵌套的
try-catch,外层的try已经可以捕获内部所有错误,简化代码结构。 - 可以给哈希函数添加盐轮数配置(比如bcrypt的10),平衡安全性和性能。
内容的提问来源于stack exchange,提问作者Miguel Ângelo Freitas
相关产品推荐
相关产品推荐

