9

I'm wondering how to use Hash::needsRehash() as I'm struggling to see using the documentation exactly what it's for.

if (Hash::needsRehash($hashed)) {
    $hashed = Hash::make('plain-text');
}

What exactly causes Hash::needsRehash() to return true or false, does it return true if the hashed password is in another hash (such as MD5, SHA1 etc)?

In the case that your database is full of hashes in another algorithm and Hash::needsRehash() returns true, how would you rehash the users password so that it's they're up to date? You can't rely on the "login" password because it needs to be compared first to validate, right?

I guess maybe I'm overthinking things but I'm confused right now. Luckily my users passwords are using password_hash() anyway so shouldn't be a problem.

Jean-Luc Tallis
  • 315
  • 1
  • 4
  • 11

4 Answers4

4

Hash::needsReHash() just calls php's built-in password_needs_rehash function. A helpful comment in the docs is:

// Check if a newer hashing algorithm is available
// or the cost has changed
if (password_needs_rehash($hash, PASSWORD_DEFAULT, $options)) {

So Hash::needsReHash() will return false if and only if hashing algorithm has changed (since you're not passing any options such as cost).

As for how and when to use this, you can only rehash a user's password when you have it -- e.g. when they're logging in. So during the login process, you check if their stored password's algorithm differs from your current algorithm, and if so, you replace their stored password hash with a new one.

Ben Claar
  • 3,285
  • 18
  • 33
  • Clear enough. My other concern still stands then. If your current user passwords need rehashing, how would you rehash them if you can't validate a users real password? – Jean-Luc Tallis Jul 25 '15 at 13:53
  • I've updated my answer; you're right, you cannot rehash a password unless you have it. – Ben Claar Jul 25 '15 at 13:59
  • 1
    You CAN always validate the user's password; when PHP stores a password, it also stores the hash that was used. So PHP is able to validate passwords even after the hash changes. – Ben Claar Jul 25 '15 at 14:01
  • 2
    Is the current cost embedded into the hash? That is, do I need another column to store this value, or is this all handled automatically? – Cruncher Mar 06 '17 at 15:56
  • 1
    @Cruncher the current cost is embedded in the `bcrypt` result. This answer has a good explanation: https://stackoverflow.com/questions/6832445/how-can-bcrypt-have-built-in-salts#answer-6833165 – cherdt Mar 08 '20 at 15:17
4

This seems to be how to do it in Laravel 5.6

Put this in your LoginController:

protected function authenticated(Request $request, $user) {
    if (Hash::needsRehash($user->password)) {
        $user->password = Hash::make($request->password);
        $user->save();
    }
}

https://laravel.com/docs/5.6/hashing#basic-usage

Ryan
  • 22,332
  • 31
  • 176
  • 357
3

The method returns true when PHP is updated and a new/better default algorithm was added or any other parameters changed. This lets you automatically take advantage of it without updating your code.

This method is used when a user is logging in as that is the only time you have access to the plain-text password. After confirming it is correct according to the old hash, you take the plain text password, rehash it, and put it back into the database for future use.

For a hypothetical example, lets say that right now the algorithm is md5() 10k times. In PHP7, it was updated to sha512() 15k times. If the hash is in the $count|$algo|$hash format, the method can tell when a hash is outdated. Since the old algorithm was not removed, you can still validate the password with old parameters before rehashing.

Note: obviously using md5()/sha512() is a bad idea. I'm just using them as examples.

Anonymous
  • 11,740
  • 3
  • 40
  • 50
0

I do not know what exactly the word 'use' here means but one of the uses that I found from my experience of this code is to prevent the password from being rehashed multiple times in Laravel. This function also tells Laravel not to hash a already hashed password. Let me give you an example. Previously, I had a following code for saving passwords in my Laravel model.

public function setPasswordAttribute($password)
    {       
            $this->attributes['password'] = Hash::make($password);
    }

What this code did was: it hashed the password before storing it in the database so that I did not had to call the make:hash function in multiple functions inside my controller. But the problem I faced was when I used the Laravel built in function called

public function logoutOtherDevices();

What this function did was it took my password attribute and rehashed it but since my model also hashed password before storing it in the database there was a double hash and my password never worked again after using log out other devices function and user had to use forgot password feature every time. Now when I used Hash::needsRehash(), it solved the problem of double hashing before storing and the password issue was solved. Here is how I implemented it in my model.

 public function setPasswordAttribute($password)
    {
        // Check if the given password is already hashed
        if (Hash::needsRehash($password)) {
                // If it is not hashed, hash it before setting the attribute
                $this->attributes['password'] = Hash::make($password);
        } else {
            // If it is already hashed, don't hash it again
            $this->attributes['password'] = $password;
        }
    }

So in summary: You can also use it to prevent your password from being hashed two times and possibly prevent password errors. This is completely based on my experience.

The Laravel documentation also tries to suggest something like this

https://laravel.com/docs/10.x/hashing#determining-if-a-password-needs-to-be-rehashed

Prakhar Gyawali
  • 527
  • 4
  • 18