用户重置密码时如何安全比较两个不同的hashed password
哈希密码对比实现方案
首先明确核心前提:单向哈希算法不存在可逆的unhash操作,该思路完全不可行。以下是不同场景下的安全实现方案:
场景:重置密码时校验新密码是否与历史密码重复(该业务场景下的最常见需求)
这是对应场景的标准实现逻辑:
- 存储用户历史密码哈希时,需要保留每个历史哈希对应的完整算法参数(包括盐值、迭代次数、内存参数等,行业标准的哈希方案如bcrypt、Argon2生成的哈希串本身就会把这些参数拼接在结果里,不需要额外单独存储)
- 用户提交新的重置密码明文时,逐一对每条历史哈希执行标准密码校验操作:用历史哈希里的参数对新明文做哈希,对比生成的结果是否和历史哈希一致
- 只要任意一条历史哈希校验通过,就判定新密码和旧密码重复,拒绝本次重置请求
场景:直接对比两个已有的哈希串是否对应同一个明文
如果没有对应的明文、只有两个哈希串,要判断是否同源,仅在以下两种条件下可实现:
- 两个哈希使用无盐/固定盐的相同哈希算法生成:直接逐位对比两个哈希串即可,但注意该类哈希方案本身不符合密码存储的安全要求,不建议在生产环境使用
- 两个哈希使用带随机盐的相同算法生成:必须拿到其中至少一个哈希对应的盐和算法参数,同时拿到原始明文,才能通过重新哈希明文的方式校验是否和另一个哈希匹配,没有其他捷径
安全注意事项
- 所有哈希对比操作必须使用时序安全的比较函数,避免时序攻击。不要直接用编程语言自带的普通字符串相等判断(比如
==运算符),要用密码学库内置的哈希比较方法:- Node.js:用
crypto.timingSafeEqual(a, b) - Python:用
hmac.compare_digest(a, b) - Java:用
MessageDigest.isEqual(a, b) - Go:用
subtle.ConstantTimeCompare(a, b) == 1
- Node.js:用
- 生产环境禁止使用MD5、SHA1等不安全的哈希算法存储密码,必须用bcrypt、Argon2id、PBKDF2等行业标准的慢哈希方案
内容的提问来源于stack exchange,提问作者cyphenom
相关产品推荐
相关产品推荐

