从NodeJS 8.x升级到NodeJS 14.x后错误密码可通过身份验证问题
问题根因排查&解决方案
1. 最高概率触发原因:bcrypt-as-promised 与 bcryptjs 的API行为差异
- 旧包
bcrypt-as-promised的compare方法逻辑:密码匹配时返回true,不匹配时直接抛出 rejected promise,不会返回false - 新包
bcryptjs的compare方法逻辑:无论匹配与否都会返回 resolved promise,匹配返回true,不匹配返回false,只有出现系统级错误才会抛错 - 如果你之前的代码是用
try/catch包裹校验逻辑,在catch里处理密码错误的情况,替换成bcryptjs之后,输错密码不会进入catch分支,只会返回false,如果代码没有对返回值做判断直接当成校验通过处理,就会出现错误密码也能登录的问题
对应代码修正示例:
// 旧版 bcrypt-as-promised 写法(可正常拦截错误密码) try { await bcrypt.compare(inputPwd, storedPwd) // 走到此处默认校验通过 loginSuccess() } catch (e) { // 密码不匹配会进入该分支,返回登录失败 loginFail() } // 替换为 bcryptjs 后的正确写法 try { const isMatch = await bcrypt.compare(inputPwd, storedPwd) if (!isMatch) { loginFail() return } loginSuccess() } catch (e) { // 仅系统异常会进入该分支 loginFail() }
2. 次优先级排查点:sequelize@4 与 Node.js 14 的兼容性问题
sequelize@4 官方支持的最高 Node.js 版本为10.x,在 Node.js 14 上运行确实会出现未定义行为:
- 检查用户模型的密码字段 getter/setter 钩子是否正常触发,是否存在存密码时未做hash、直接存储明文的情况
- 检查登录查询逻辑是否能正确取出存储的hash密码,是否存在字段返回空、或者类型转换错误的问题
- 升级sequelize到v6 LTS版本是更稳妥的方案,升级时注意同步调整
pg对应的驱动适配逻辑
3. 快速验证手段
在登录接口逻辑中新增日志打印三个值:用户输入的明文密码、数据库取出的存储hash值、bcrypt.compare的返回值,可快速定位到底是bcrypt调用逻辑的问题还是ORM取数的问题。
内容的提问来源于stack exchange,提问作者darknet
相关产品推荐
相关产品推荐

