Ruby BCrypt哈希比较 [英] Ruby BCrypt hash comparison

查看:117
本文介绍了Ruby BCrypt哈希比较的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Sinatra和BCrypt实现看似非常简单的身份验证方法,但显然我遗漏了一些东西...

为用户预先分配了一个临时密码,该密码以明文形式存储在数据库中.

我根据临时密码进行身份验证,然后创建一个salt和password_hash并将它们作为字符串写入db(在这种情况下为mongo).

要进行身份验证,我从数据库和用户密码中获取盐进行比较.

post "/password_reset" do
  user = User.first(:email => params[:email], :temp_password => params[:temp_password])
  if dealer != nil then
  password_salt = BCrypt::Engine.generate_salt
  password_hash = BCrypt::Engine.hash_secret(params[:password], password_salt)
  user.set(:password_hash => password_hash)
  user.set(:password_salt => password_salt)
  end
end

post "/auth" do
  @user = User.first(:email => params[:email])
  @user_hash = BCrypt::Password.new(@user.password_hash) #because the password_hash is  stored in the db as a string, I cast it as a BCrypt::Password for comparison
  if @user_hash == BCrypt::Engine.hash_secret(params[:password], @user.password_salt.to_s)   then
    auth = true
  else
    auth = false
  end
end

BCrypt :: Engine.hash_secret(params [:password],password_salt)返回的值与数据库中存储的值不同(均为BCrypt :: Password类,但它们不匹配)./p>

我在这里想念什么?在此先感谢您的任何见解!

马克

解决方案

BCrypt::PasswordString的子类,它Engine类,而只是使用Password类.您不需要自己管理盐,bcrypt会处理这些盐并将其包含在密码哈希字符串中:

password_salt = BCrypt::Engine.generate_salt
password_hash = BCrypt::Engine.hash_secret("s3kr1t!", password_salt)

puts password_salt
puts password_hash

产生这样的东西:

 $2a$10$4H0VpZjyQO9SoAGdfEB5j.
$2a$10$4H0VpZjyQO9SoAGdfEB5j.oanIOc4zp3jsdTra02SkdmhAVpGK8Z6
 

如果运行它,您会得到一些不同的东西,因为会生成不同的盐,但是您可以看到密码哈希中包含了盐.

在您的情况下,您需要这样的东西:

post "/password_reset" do
  user = User.first(:email => params[:email], :temp_password => params[:temp_password])
  if dealer != nil then
    password_hash = BCrypt::Password.create(params[:password])
    user.set(:password_hash => password_hash) # no need to store the salt separately in the database
  end
end

post "/auth" do
  @user = User.first(:email => params[:email])
  @user_hash = BCrypt::Password.new(@user.password_hash)
  if @user_hash == params[:password]  then # overridden == method performs hashing for us
    auth = true
  else
    auth = false
  end
end

I'm trying to implement what seems like a very simple authentication approach using Sinatra and BCrypt but clearly I'm missing something...

Users are preassigned a temporary password which is stored in plaintext in the db.

I authenticate against the temp password and then create both a salt and password_hash and write them as strings to the db (mongo in this case).

To authenticate I fetch the salt from the db and user password to compare.

post "/password_reset" do
  user = User.first(:email => params[:email], :temp_password => params[:temp_password])
  if dealer != nil then
  password_salt = BCrypt::Engine.generate_salt
  password_hash = BCrypt::Engine.hash_secret(params[:password], password_salt)
  user.set(:password_hash => password_hash)
  user.set(:password_salt => password_salt)
  end
end

post "/auth" do
  @user = User.first(:email => params[:email])
  @user_hash = BCrypt::Password.new(@user.password_hash) #because the password_hash is  stored in the db as a string, I cast it as a BCrypt::Password for comparison
  if @user_hash == BCrypt::Engine.hash_secret(params[:password], @user.password_salt.to_s)   then
    auth = true
  else
    auth = false
  end
end

The value returned by BCrypt::Engine.hash_secret(params[:password], password_salt) is different than what is stored in the db (both are of class BCrypt::Password, but they don't match).

What am I missing here? Many thanks in advance for any insight!

Marc

解决方案

BCrypt::Password is a subclass of String, and it overrides the == method to make checking passwords easier. When you do

if @user_hash == BCrypt::Engine.hash_secret(params[:password], @user.password_salt.to_s)

you end up performing the hash twice, and so they don’t match. If you compared directly with @user.password_hash rather than using BCrypt::Password.new you should see that they match.

The more "correct" way to use bcrypt-ruby for passwords is to not use the Engine class at all, just the Password class. You don’t need to manage the salt yourself, bcrypt takes care of that and includes it in the password hash string:

password_salt = BCrypt::Engine.generate_salt
password_hash = BCrypt::Engine.hash_secret("s3kr1t!", password_salt)

puts password_salt
puts password_hash

produces something like this:

$2a$10$4H0VpZjyQO9SoAGdfEB5j.
$2a$10$4H0VpZjyQO9SoAGdfEB5j.oanIOc4zp3jsdTra02SkdmhAVpGK8Z6

You’ll get something slightly different if you run it, since a different salt will be generated, but you can see that the password hash includes the salt.

In your case, you want something like this:

post "/password_reset" do
  user = User.first(:email => params[:email], :temp_password => params[:temp_password])
  if dealer != nil then
    password_hash = BCrypt::Password.create(params[:password])
    user.set(:password_hash => password_hash) # no need to store the salt separately in the database
  end
end

post "/auth" do
  @user = User.first(:email => params[:email])
  @user_hash = BCrypt::Password.new(@user.password_hash)
  if @user_hash == params[:password]  then # overridden == method performs hashing for us
    auth = true
  else
    auth = false
  end
end

这篇关于Ruby BCrypt哈希比较的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆