Ruby BCrypt哈希比较

Ruby BCrypt哈希比较,ruby,bcrypt,Ruby,Bcrypt,我正在尝试使用Sinatra和BCrypt实现一种看似非常简单的身份验证方法,但显然我遗漏了一些东西 用户预先分配一个临时密码,该密码以明文形式存储在数据库中 我根据临时密码进行身份验证,然后创建salt和password_散列,并将它们作为字符串写入db(本例中为mongo) 为了进行身份验证,我从数据库中获取salt并与用户密码进行比较 post "/password_reset" do user = User.first(:email => params[:email], :te

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

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

我根据临时密码进行身份验证,然后创建salt和password_散列,并将它们作为字符串写入db(本例中为mongo)

为了进行身份验证,我从数据库中获取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
BCrypt::Engine.hash_secret(params[:password],password_salt)返回的值与数据库中存储的值不同(两者都属于BCrypt::password类,但不匹配)

我错过了什么?非常感谢您的洞察力


Marc

BCrypt::Password
String
的一个子类,它使检查密码更容易。当你这样做的时候

if @user_hash == BCrypt::Engine.hash_secret(params[:password], @user.password_salt.to_s)
最后执行两次哈希,因此它们不匹配。如果您直接与
@user.password\u hash
进行比较,而不是使用
BCrypt::password.new
进行比较,您应该会看到它们匹配

使用bcrypt ruby作为密码的更“正确”的方法是根本不使用
引擎
类,只使用
密码
类。您不需要自己管理salt,bcrypt会处理它并将其包含在密码哈希字符串中:

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

puts password_salt
puts password_hash
产生如下结果:

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
$2a$10$4H0VpZjyQO9SoAGdfEB5j。
$2a$10$4H0VpZjyQO9SoAGdfEB5j.oanIOc4zp3jsdTra02SkdmhAVpGK8Z6
如果运行它,您将得到一些稍微不同的结果,因为将生成不同的salt,但是您可以看到密码散列包含salt

在您的情况下,您需要以下内容:

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

非常感谢你。这正是我所缺少的,非常有效。我可以停止拔头发(直到下一件事)。你可以做@user\u hash.is\u password?参数[:密码]而不是==。。。我认为它更清晰,更容易出错,因为如果您不知道==被覆盖,并反转比较顺序(params[:password]===@user\u hash),它将返回false。。。