2012-08-19 26 views
12

Tôi đang cố gắng để thực hiện những gì có vẻ như một cách tiếp cận xác thực rất đơn giản sử dụng Sinatra và bcrypt nhưng rõ ràng tôi là thiếu một cái gì đó ...của Ruby bcrypt băm so

Người dùng được gán trước một mật khẩu tạm thời được lưu trữ trong bản rõ trong db.

Tôi xác thực dựa vào mật khẩu tạm thời và sau đó tạo cả muối và password_hash và viết chúng dưới dạng chuỗi vào db (mongo trong trường hợp này).

Để xác thực tôi tìm nạp muối từ db và mật khẩu người dùng để so sánh.

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 

Giá trị trả về bởi bcrypt :: Engine.hash_secret (params [: mật khẩu], password_salt) là khác với những gì được lưu trữ trong db (cả hai đều của lớp bcrypt :: Password, nhưng họ không trận đấu).

Tôi thiếu gì ở đây? Cảm ơn nhiều trước vì bất kỳ thông tin chi tiết nào!

Marc

Trả lời

23

BCrypt::Password là một lớp con của String, và nó overrides the == method để kiểm tra mật khẩu dễ dàng hơn. Khi bạn làm

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

bạn kết thúc thực hiện băm hai lần, và vì vậy họ không khớp. Nếu bạn so sánh trực tiếp với @user.password_hash thay vì sử dụng BCrypt::Password.new, bạn sẽ thấy rằng chúng khớp với nhau.

Cách "sử dụng bcrypt-ruby" nhiều hơn cho đúng mật khẩu là không sử dụng lớp Engine, chỉ cần ở lớp Password. Bạn không cần phải quản lý muối cho mình, bcrypt chăm sóc đó và bao gồm nó trong chuỗi mật khẩu băm:

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

puts password_salt 
puts password_hash 

sản xuất cái gì đó như thế này:

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

Bạn sẽ nhận được một cái gì đó hơi khác nhau nếu bạn chạy nó, vì một muối khác sẽ được tạo ra, nhưng bạn có thể thấy rằng mật khẩu băm bao gồm muối.

Trong trường hợp của bạn, bạn muốn một cái gì đó như thế này:

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 
+1

Cảm ơn bạn rất nhiều. Đó là chính xác những gì tôi đã mất tích, hoạt động hoàn hảo. Tôi có thể ngừng kéo tóc của tôi ra (cho đến khi điều tiếp theo). – user1553220

+1

bạn có thể thực hiện @ user_hash.is_password? params [: password] thay vì == ... Tôi nghĩ rằng nó rõ ràng hơn và dễ bị lỗi hơn, bởi vì nếu bạn không biết rằng == đã bị ghi đè và đảo ngược thứ tự so sánh (params [: password] == @user_hash), nó sẽ trả về false ... – rizidoro

Các vấn đề liên quan