为什么BCrypt不再接受哈希?

psy*_*ave 5 ruby-on-rails bcrypt-ruby mongodb-3.6 fedora-28

上周我将Fedora升级到全新的28版本,其中mongodb升级到3.6.请参阅升级到Fedora 28后如何修复mongodb服务?因为我设法解决了我的第一个问题,即mongod将不再启动.现在我在使用同一个数据库的Rails应用程序上面临另一个问题.

这很可能与mongodb升级无关,但我认为值得提供上下文并且不要错过没有提供足够的上下文的解决方案.

因此,自系统升级以来,对此Rails项目的任何登录尝试都将失败BCrypt::Errors::InvalidHash in Devise::SessionsController#create ,并在bcrypt (3.1.11) lib/bcrypt/password.rb:60:ininitialize'`处引发错误.在项目的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'
Run Code Online (Sandbox Code Playgroud)

我试图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
Run Code Online (Sandbox Code Playgroud)

相应的测试如下:

  def valid_hash?(h)
    h =~ /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/
  end
Run Code Online (Sandbox Code Playgroud)

散列本身是通过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'),它实际上是一个相当长的字符串,其开始看起来很平常,但最终会出现最可能是错误生成的序列:

"$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…"
Run Code Online (Sandbox Code Playgroud)

如果它可能有任何兴趣(大约32Ko!),我可以提供整个哈希的转储.

psy*_*ave 8

这里是一个回避解决方案,使rspecbcrypt通所有测试成功一次.

在等待合适的解决方案时,这真的是一个糟糕的黑客,但直到那时才完成工作.只需改变~/.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).*/, '')
Run Code Online (Sandbox Code Playgroud)

也就是说,如果有的话,从第一个"\ x00"或"\n"出现开始中继字符串.

信用说明:此版本的黑客攻击是Andrey Sitnik提出的,在发现它之前,我取代了我在这里独立提出的版本.

之后,BCrypt :: Password#create将再次运行:

> BCrypt::Password.create('TestPassword')
=> "$2a$10$YPRnQF3ZihXHpa9kSx7Mpu.j28PlbdwaNs2umSQvAGkS.JJ.syGye"
Run Code Online (Sandbox Code Playgroud)


Xtr*_*ity 5

我在一个(非常)旧的应用程序和 BCrypt 上遇到了这个问题3.1.10。升级以3.1.12解决问题。:)