14
Nov '17

Automatically Transitioning Password Storage in Laravel

I always make security my top priority in any application I build. This is fine when I build something from scratch, but when I inherit a site I often encounter some interesting challenges. In this instance I was building a new application to sit on an existing database, which was in pretty decent state other than the fact that all user records had MD5 passwords!
I couldn’t force all users to go through a password reset process, and I wasn’t going to start trying to crack all the passwords (yes, yes, I know that could have been done but it’s too black-hat for my taste), so I had to think of a mechanism to convert the passwords transparently to the users.
I came up with a system that overrides Laravel’s standard login function, within the Illuminate\Foundation\Auth\AuthenticatesUsers class to do the following:

  • Find the user being logged in by their email address
  • Check if the user record has been flagged as ‘safe’ (this is just an additional boolean column on the record)
  • If not it compares the user record’s password with an MD5 hash of the submitted password
  • If the MD5 hash matches then it produces a new secure hash (bcrypt is currently the Laravel standard) of the submitted password, stores it on the user record and flips the ‘safe’ flag
  • Then the main Laravel login function is called, which takes it all from there
use AuthenticatesUsers {
    login as coreLogin;
}
/**
 * Handle a login request to the application.
 *
 * @param  \Illuminate\Http\Request $request
 * @return \Illuminate\Http\Response
 */
public function login(Request $request)
{
    $credentials = $this->getCredentials($request);

    if(!empty($credentials['email']) && !empty($credentials['password'])) {
        if($user = \App\Model\User::where('email', $credentials['email'])->where('active', true)->first()) {
            if(!$user->safe) {
                if($user->password == md5(trim($credentials['password']))) {
                    $user->password = \Hash::make(trim($credentials['password']));
                    $user->safe = true;
                    $user->save();
                }
            }
        }
    }

    return $this->coreLogin($request);
}

And there we have it. Anytime a user with an old password logs in they will have it transparently updated and secured.

Leave a Reply