上周我将Fedora升级到全新的28版本,其中mongodb升级到3.6。请参阅How to repair mongodb service after an upgrade to Fedora 28?,了解我是如何解决我的第一个问题,即mongod将不再启动。现在我在Rails应用程序上面临另一个使用同一数据库的问题。
这很可能与mongodb升级无关,但我认为值得提供这样的背景,并且不会因为没有提供足够的内容而错过解决方案。
因此,自系统升级以来,对此Rails项目的任何登录尝试都将失败并出现BCrypt::Errors::InvalidHash in Devise::SessionsController#create
错误,在bcrypt (3.1.11) lib/bcrypt/password.rb:60:in
初始化'`时引发错误。在项目的Rails控制台中进一步分析,似乎对此方法的任何调用都将失败:
> BCrypt::Password.create('TestPassword')
BCrypt::Errors::InvalidHash: invalid hash
from /home/psychoslave/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bcrypt-3.1.11/lib/bcrypt/password.rb:60:in `initialize'
我尝试bundle
卸载/重新安装bcrypt
,甚至使用bcrypt gem的github存储库版本,但它没有改变任何东西。
看/home/psychoslave/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bcrypt-3.1.11/lib/bcrypt/password.rb:60:in
初始化'`,问题似乎是哈希无效。
# Initializes a BCrypt::Password instance with the data from a stored hash.
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
相应的测试如下:
def valid_hash?(h)
h =~ /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/
end
哈希本身是通过BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(cost))
创建的,我在平台中使用调用__bc_crypt(secret.to_s, salt)
,它似乎在调用bcrypt-3.1.11/ext/mri/bcrypt_ext.c。
更重要的是,在binding.pry
方法中添加valid_hash?
,可以查看为BCrypt::Password.create('TestPassword')
调用返回的哈希值是什么,它是&#39}实际上是一个相当长的字符串,其开始似乎很平常,但最终会产生最可能错误的序列:
"$2a$10$Eb1f8DSkGh4G1u5GicyTYujBk6SwFXKYCH.nqxapmBlqJ0eFYdX32\x00\x00\x00\x00\xD1F\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00T\xBD\x02\x00\x00\x00\x00\x00\xF1V\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xE2\xB0\x02\x00\x00\x00\x
00\x00AW\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00 \x04\x00\x00\x00\x00\x00\x00\x86\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xB5\xF8\x0E\x00\x00\x00\x00\x00q\xD8\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00…"
如果它可能有任何兴趣(约32Ko!),我可以提供整个哈希的转储。
答案 0 :(得分:8)
这是一个规避解决方案,使rspec
bcrypt
再次成功通过所有测试。
在等待合适的解决方案时,这真的是一个糟糕的黑客,但直到那时才完成工作。只需更改~/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bcrypt-3.1.11/lib/bcrypt/engine.rb
(当然要适应的路径),第51行来自:
- __bc_crypt(secret.to_s, salt)
+ __bc_crypt(secret.to_s, salt).gsub(/(\n|\x00).*/, '')
也就是说,从第一个“\ x00”或“\ n”出现开始,将字符串作为主干,如果有的话。
信用说明:this version of the hack was proposed Andrey Sitnik,在发现之前我替换了我在此提出的那个。
之后,BCrypt :: Password#create将再次运行:
> BCrypt::Password.create('TestPassword')
=> "$2a$10$YPRnQF3ZihXHpa9kSx7Mpu.j28PlbdwaNs2umSQvAGkS.JJ.syGye"
答案 1 :(得分:0)
我在一个(非常)旧的应用程序和BCrypt 3.1.10
中遇到了这个问题。升级到3.1.12
可解决此问题。 :)