为什么BCrypt不再接受哈希?

时间:2018-05-07 11:23:49

标签: ruby-on-rails bcrypt-ruby mongodb-3.6 fedora-28

上周我将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!),我可以提供整个哈希的转储。

2 个答案:

答案 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可解决此问题。 :)