John Main Logo

John Main

Code. Design. Hosting. Maintenance.

14
Nov '17

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.