heartcombo / devise

Flexible authentication solution for Rails with Warden.
http://blog.plataformatec.com.br/tag/devise/
MIT License
23.9k stars 5.54k forks source link

sign in issue with module Encryptor and wrong value returned by ::BCrypt::Engine.hash_secret() after session expiration #5388

Open aeigus opened 3 years ago

aeigus commented 3 years ago

Environment

devise :database_authenticatable, :registerable, :confirmable, :lockable,
         :timeoutable, :trackable, :recoverable, :rememberable, :validatable,
         password_length: 6..64

Current behavior

I have an application where sessions expire in 12 hours, config.timeout_in is also set to 12.hours. After session expires and if a browser (I am using Brave, which is a fork from Chrome) is still open, a user won't be able to sign in with authentication error from devise. I ran a debug session and found out that the following code in devise/encryptor.rb will return a different hashed password value than that stored in db:

password = ::BCrypt::Engine.hash_secret(password, bcrypt.salt)

As the result, Devise.secure_compare will return false. Once I restart the browser, I would be able to successfully sign in, as the hashed value returned by ::Bcrypt::Engine.hash_secret() will then be identical to encrypted_password in the User model.

Stepping through self.compare(klass, hashed_password, password) in Decryptor:

# arguments
> hashed_password
=> "$2a$12$yhr1pRFrdWTeYzCeuJCnA.tibFxeQK.4jdzRa5jpi28jQp.lB67u." 
> password
=> "nxuBdUiS6wjZUQq"

bcrypt   = ::BCrypt::Password.new(hashed_password)
> bcrypt
=> "$2a$12$yhr1pRFrdWTeYzCeuJCnA.tibFxeQK.4jdzRa5jpi28jQp.lB67u."
> bcrypt.salt
=> "$2a$12$yhr1pRFrdWTeYzCeuJCnA."

password = ::BCrypt::Engine.hash_secret(password, bcrypt.salt)
> password
=> "$2a$12$yhr1pRFrdWTeYzCeuJCnA.GlmoiuIfYRwdtdU3vAVPvr9wOmoClqu"

Devise.secure_compare(password, hashed_password)
=> false

I am trying to understand how expired sessions affect the hashed password value returned by ::BCrypt::Engine.hash_secret(), but nothing comes to mind!

Expected behavior

password = ::BCrypt::Engine.hash_secret(password, bcrypt.salt)
> password
=> "$2a$12$yhr1pRFrdWTeYzCeuJCnA.tibFxeQK.4jdzRa5jpi28jQp.lB67u."
IvanBernatovic commented 2 years ago

@aeigus We are experiencing a similar issue at the moment, so far I traced it back to this since I know for sure some affected users are always using the valid password.

Do you have more info about this and the potential fix?

aeigus commented 2 years ago

If I remember correctly, I could do nothing to solve the issue, but it doesn't seem to appear for some time lately...