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.