Ruby BCrypt哈希比较

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

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

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

要进行身份validation,我从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 

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

我在这里想念的是什么? 非常感谢您的任何见解!

BCrypt::PasswordString的子类,它会覆盖==方法以使检查密码更容易。 当你这样做

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

你最终执行两次哈希,所以它们不匹配。 如果您直接与@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 

产生这样的东西:

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

如果运行它会有一些不同的东西,因为会生成不同的盐,但是您可以看到密码哈希包含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