Insecure functionality - Pass the hash - Ruby

Insecure functionality - Pass the hash - Ruby

Need

Secure authentication and authorization mechanisms

Context

  • Usage of Ruby for building dynamic and object-oriented applications
  • Usage of digest for generating hash values or checksums

Description

Non compliant code

        require 'digest'

def authenticate(username, password_hash)
  stored_hash = User.find_by(username: username).password_hash
  if stored_hash == password_hash
    return true
  else
    return false
  end
end
        
        

The vulnerable code above is a simple authentication function in a Ruby on Rails application. It takes a username and a password hash as inputs. The function then retrieves the stored password hash from the database for the given username and compares it with the provided password hash.

The vulnerability here is that the function is directly comparing the provided password hash with the stored hash. This is known as the "Pass The Hash" vulnerability. An attacker who has somehow obtained a hash of a user's password can pass it directly to this function and be authenticated as that user.

In this scenario, the system is not verifying that the user knows the actual password, but is only checking if the user knows the hash. If an attacker can obtain the hash (e.g., through a database breach, network interception, or other means), they can authenticate themselves as any user without needing to know or crack the actual password.

This vulnerability allows for unauthorized access and potential privilege escalation if the compromised account has higher privileges.

Steps

  • Avoid storing password hashes directly in the database. Instead, use a strong and secure password hashing algorithm like bcrypt or Argon2.
  • When authenticating a user, retrieve the stored password hash from the database and compare it with the hash of the provided password using a secure comparison function.
  • Do not compare the password hash directly with the provided password hash. Instead, use a secure comparison function that is resistant to timing attacks.
  • Implement proper session management and authentication mechanisms to prevent unauthorized access to resources within the domain.
  • Regularly update and patch the Ruby on Rails framework and its dependencies to ensure that any security vulnerabilities are addressed.
  • Educate developers about secure coding practices and the risks associated with insecure authentication mechanisms.

Compliant code

        require 'bcrypt'

def authenticate(username, password)
  user = User.find_by(username: username)
  if user && BCrypt::Password.new(user.password_hash) == password
    return true
  else
    return false
  end
end
        
        

The updated code now uses the bcrypt gem for password hashing and comparison. Bcrypt is a strong and secure password hashing algorithm that is resistant to brute-force search attacks due to its computational cost.

In the authenticate method, we first find the user by their username. If the user exists, we retrieve the stored password hash from the database and create a new BCrypt::Password object from it.

We then compare this BCrypt::Password object with the provided password using the == operator. This operator has been overridden by the bcrypt gem to perform a secure comparison that is resistant to timing attacks. It does this by hashing the provided password with the same salt that was used to hash the stored password, and then comparing the resulting hashes. This ensures that an attacker cannot use the "Pass The Hash" technique to gain unauthorized access to resources within the domain.

If the comparison returns true, the method returns true to indicate that the authentication was successful. Otherwise, it returns false.

This code should be used in conjunction with proper session management and authentication mechanisms to further enhance the security of the application. Regular updates and patches to the Ruby on Rails framework and its dependencies should also be applied to address any security vulnerabilities.

Finally, developers should be educated about secure coding practices and the risks associated with insecure authentication mechanisms to prevent similar vulnerabilities in the future.

References