Ruby BCrypt哈希比较

use*_*220 12 ruby bcrypt

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

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

我对临时密码进行身份验证,然后创建一个salt和password_hash并将它们作为字符串写入db(在本例中为mongo).

要进行身份验证,我从db和用户密码中获取salt以进行比较.

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

BCrypt :: Engine.hash_secret(params [:password],password_salt)返回的值与db中存储的值不同(两者都是BCrypt :: Password类,但它们不匹配).

我在这里错过了什么?非常感谢您的任何见解!

mat*_*att 24

BCrypt::Password是它的子类String,它覆盖了==使检查密码更容易方法.当你这样做

if @user_hash == BCrypt::Engine.hash_secret(params[:password], @user.password_salt.to_s)
Run Code Online (Sandbox Code Playgroud)

您最终执行两次哈希,因此它们不匹配.如果你直接@user.password_hash比较而不是使用BCrypt::Password.new你应该看到它们匹配.

对密码使用bcrypt-ruby的更"正确"的方法是根本不使用Engine类,只使用Password类.您不需要自己管理盐,bcrypt负责处理并将其包含在密码哈希字符串中:

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

puts password_salt
puts password_hash
Run Code Online (Sandbox Code Playgroud)

产生这样的东西:

$2a$10$4H0VpZjyQO9SoAGdfEB5j.
$2a$10$4H0VpZjyQO9SoAGdfEB5j.oanIOc4zp3jsdTra02SkdmhAVpGK8Z6
Run Code Online (Sandbox Code Playgroud)

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

在你的情况下,你想要这样的东西:

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

  • 你可以做@ user_hash.is_password吗?params [:password]而不是== ...我认为它更清晰易出错,因为如果您不知道==已被覆盖并反转比较顺序(params [:password] == @user_hash),它将返回假... (2认同)