Cracked weak credentials - PHP

Cracked weak credentials - PHP

Need

Enhancement of password security measures

Context

  • Usage of PHP 7.0 for server-side scripting and web development
  • Usage of Request for making HTTP requests
  • Usage of the User dependency for user-related functionality
  • Usage of Auth for implementing authentication and authorization in a Node.js application

Description

Non compliant code

        public function login(Request $request)
{
    $username = $request->input('username');
    $password = $request->input('password');

    $user = User::where('username', $username)->first();

    if ($user && md5($password) == $user->password) {
        Auth::login($user);
        return redirect('/home');
    } else {
        return redirect('/login')->with('error', 'Invalid credentials');
    }
}
        
        

The above code snippet is a basic login function in a Laravel application. The function accepts a request object which contains the submitted username and password from a login form. It then checks if a user with the submitted username exists in the database and if the MD5 hash of the submitted password matches the stored password for that user. If both conditions are met, the user is logged in and redirected to the home page. Otherwise, they are redirected back to the login page with an error message.

The vulnerability in this code lies in the use of the MD5 hash function for password hashing. MD5 is a widely used cryptographic hash function that produces a 128-bit (16-byte) hash value. It is commonly used to verify data integrity. However, MD5 is not suitable for password hashing due to its speed and the availability of lookup tables (rainbow tables) which can be used to reverse MD5 hashes.

This makes it easy for an attacker who gains access to the database to crack the passwords, especially if they are weak (i.e., common, short, without a mix of letters, numbers, and special characters).

Additionally, the code does not implement any form of password complexity requirements or account lockout after a certain number of failed login attempts, both of which could further mitigate the risk of password cracking.

To summarize, the use of MD5 for password hashing, combined with the lack of password complexity requirements and account lockout mechanisms, makes this code vulnerable to password cracking attacks.

Steps

  • Replace the MD5 hashing algorithm with a stronger one such as bcrypt or Argon2.
  • Implement a salt for each user password. A salt is a random string that is added to the password before hashing. This makes the hash unique even for identical passwords and makes it harder for an attacker to use precomputed tables to crack the password.
  • Consider using a library or framework function for password hashing and verification. Many languages have built-in functions for this that are well-tested and considered secure.
  • Implement a password policy that enforces complexity requirements. This could include a minimum length, and requirements for uppercase and lowercase letters, numbers, and special characters.
  • Consider implementing account lockouts or delays after a certain number of failed login attempts to protect against brute force attacks.

Compliant code

        public function login(Request $request)
{
    $username = $request->input('username');
    $password = $request->input('password');

    $user = User::where('username', $username)->first();

    if ($user && Hash::check($password, $user->password)) {
        Auth::login($user);
        return redirect('/home');
    } else {
        return redirect('/login')->with('error', 'Invalid credentials');
    }
}
        
        

The updated code now uses Laravel's built-in Hash::check method to verify the password. This method uses the bcrypt hashing algorithm, which is much stronger than MD5. Bcrypt automatically handles the creation of a salt for each password, which is a random string that is added to the password before hashing. This makes the hash unique even for identical passwords and makes it harder for an attacker to use precomputed tables to crack the password.

In addition to using a stronger hashing algorithm and adding a salt, the Hash::check method also provides a timing-safe comparison to prevent timing attacks.

To further enhance security, consider implementing a password policy that enforces complexity requirements. This could include a minimum length, and requirements for uppercase and lowercase letters, numbers, and special characters. Also, consider implementing account lockouts or delays after a certain number of failed login attempts to protect against brute force attacks.

References