You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何传入BCrypt哈希作为盐时,String.crypt能生成匹配的哈希?

问题:为何同一方法能同时验证String.crypt和BCrypt哈希?

我发现部分代码使用String.crypt处理密码哈希,于是尝试寻找可同时验证BCrypt哈希与旧版String.crypt哈希的方法。意外发现以下方法对两种哈希均能正常工作,但不清楚其原理:

def check_password(password, stored_hash)
  password.crypt(stored_hash) == stored_hash
end

测试情况如下:

string_crypt_pass = "mysuperpass".crypt("$1$abasasa")
bcrypt_pass = BCrypt::Password.create("mysuperpass").to_s

check_password("mysuperpass", string_crypt_pass) #true
check_password("mywrongpass", string_crypt_pass) #false

check_password("mysuperpass", bcrypt_pass) #true
check_password("mywrongpass", bcrypt_pass) #false

请问该方法为何能生效?


解答

这个方法能生效的核心原因是Ruby的String#crypt方法本身具备自动适配哈希算法的能力,具体逻辑分两种情况:

1. 对String.crypt生成的哈希的处理

String#crypt生成的哈希格式自带算法标识,比如例子里的$1$abasasa$...:

  • $1$是MD5算法的标识(crypt支持多种哈希算法,通过前缀区分)
  • 紧随其后的abasasa是盐值
  • 最后一段是密码的哈希结果

当调用password.crypt(stored_hash)时,方法会自动从传入的stored_hash中解析出算法标识+盐值(也就是$1$abasasa),然后用对应的MD5算法重新计算输入密码的哈希。如果密码正确,重新计算的结果会和原stored_hash完全一致,比对返回true;密码错误则结果不同,返回false。

2. 对BCrypt生成的哈希的处理

BCrypt生成的哈希格式是$2a$xx$...(xx是成本因子,比如10):

  • $2a$是BCrypt算法的标识
  • 主流系统的crypt库都支持BCrypt算法,Ruby的String#crypt会识别这个标识
  • 方法会从stored_hash中提取出成本因子和盐值,用BCrypt算法重新计算输入密码的哈希

同样,密码正确时重新计算的哈希会和原BCrypt哈希完全匹配,比对成立;密码错误则不匹配。

简单来说,String#crypt的设计逻辑就是:传入已有的哈希作为参数时,它会自动复用该哈希里的算法和盐信息,重新计算密码哈希,所以不管是旧版crypt生成的哈希还是BCrypt哈希,都能通过这种方式完成验证。


内容的提问来源于stack exchange,提问作者hat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 16:14:58