最近,当我试图保存一条带有密码的记录时,我开始收到BCrypt "无效散列 "的错误,于是我查看了BCrypt代码,发现了以下验证密码的方法。
def valid_hash?(h)
h =~ /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/
end
该方法由 initialize
方法。
def initialize(raw_hash)
if valid_hash?(raw_hash)
self.replace(raw_hash)
@version, @cost, @salt, @checksum = split_hash(self)
else
raise Errors::InvalidHash.new("invalid hash")
end
end
以下密码
"PassiveForbearenceFox"
"VindictivePurpleAlligator12345"
"LostBlueLizard!@#$1234"
都返回 "无效散列 "错误。
我深究了一下,发现regex是在检查密码的哈希值,但得到传递的哈希值有一个流的 /x00
的后面。
例如,如果我使用密码 "LostBlueLizard!@#1234",那么传递给挑战regex的哈希值是。
"$2a$11$NcmldbbyCDfumGYALgYhfuIQt2FZ8gpbVCQfuiVlwjhCtkD2ndDFy\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\...
以此类推,比我能滚动的更远。
如果我去掉 "LostBlueLizard!@#1234 "这个密码,传递给我的哈希值是:等等,远远超过我的滚动范围。\x00
的,并通过 $2a$11$NcmldbbyCDfumGYALgYhfuIQt2FZ8gpbVCQfuiVlwjhCtkD2ndDFy
,它通过了regex。
为什么哈希有这些字符?我无法证明之前没有这些字符,但我的密码一直被接受,直到最近。
另外,实际上是 raw_hash
的输入。initialize
方法,这是一个包含所有的 \x00
s. 所以在某个地方有代码生成了错误的哈希值,并将其传给了 initialize
,但我在整个 gem 的代码库中搜索 "initialize "一词,并没有这样的结果,所以我找不到哈希到底是在哪里生成的。
我进一步追踪了这个问题,到了 BCrypt::Engine.create
方法,该方法调用 __bc_crypt
,这就是返回错误的哈希值的原因。__bc_crypt
实际上是来自C源文件 ext/mri/bcrypt_ext.c
这超出了我的调查能力。
我把BCrypt从3.1.11更新到3.1.13,现在可以正常使用了。我不确定这是否是一个错误,但重点是它现在工作了。
这并不意味着Bcrypt的valid_hash?方法是错误的,这意味着存储的密码,那个是无效的或nil,这与有效的哈希系统不符
你可能要加上
has_secure_password
如果那个没有,然后检查password_digest字段后。