PHPBuilder - Implementing Secure Passwords in PHP 5.5



RSS Twitter
Articles Site Operation

Implementing Secure Passwords in PHP 5.5

by: Marc Plotz
|
January 22, 2014

Introduction

PHP has always had a few simple ways to implement password hashing to an extent. MD5 and SHA1 are examples of this, but the security of these methods is not what it should be. Many developers use MD5 and SHA1 without even adding a SALT, which is a string that helps to add complexity to the application. Some developers use something as awful as base 64 encoding and decoding simply because they can be easily manipulated. But these things are not secure folks, and the clever people who want to hack your site or steal your money can see right through them. Yes, they can.

 

What we need is a secure password encryption mechanism that uses SALT and perhaps even something else to help us safely encrypt our passwords for later use. It would even be nice if we could throw in a method to compare our encrypted password with an unencrypted one, removing the need for us to go loco and use base 64 encoding. It gives me gooseflesh. In a bad way.

 

PHP 5.5 Secure Password API

Lucky for us, the folks at PHP have thought about this long and hard, and the result is a very simple PHP password hashing API that is not only easy to use, but fast and secure. How does it work? This is the old (pre-PHP5.5 way) of creating a hashed password:

 

$hash = md5($password . $hash); 

 

This way is not bad--it works--but it isn't great. The encryption is limited and there are actually folks who have logs that can decrypt many (but not nearly all) md5 hashes. It's kind-of safe, and that's only OK if you don't mind telling your client his shiny new website is kind-of safe.

 

There is a lot that can go wrong here. Firstly, you MUST use a SALT. If you don't, your security WILL be compromised. Surely you realize that there is only one MD5 encryption per string. This means that for every string there is exactly one MD5 pattern for that string. This is clearly not safe.

 

The new, better way of doing this is:

 

$hash = password_hash($password, PASSWORD_DEFAULT); 

 

As you can see, the password_hash() function will create an encrypted password using the default algorithm, which is currently bcrypt(), and sets the default load factory (cost) at 10. The result will be a 60 character string that looks something like this:

 

$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

 

This is much more secure for a few reason, the first of which is that we are creating a 60 character string, compared with a 32 character string. Obviously it is harder to crack a 60 character password hash than it is to crack as 32 character one. The difference in password strength is somewhere in the hundreds of millions times stronger. The second thing is that even if you can figure out what SALT we have used (which in this case, you cannot), you still have no idea what COST we are using, and as you will see below, both of these are variable. This means we have something resembling a secure password that cannot be backward engineered without knowing the COST as well as the SALT.

 

Now comes the fun part. We can set our own SALT and COST and pass it into the function, as follows:

 

$options = [
	'cost' => 11,
	'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM)
];

$password = password_hash('someNewPassword', PASSWORD_BCRYPT,  $options); 

 

As you can see, we have now set our own encryption parameters, making it virtually impossible for anyone else to guess what type of password they are going to be looking for. Secure is good. This is better. Not only do we have a SALT, but we have a COST too. We also have the choice of which password algorithm to use, making it yet harder to crack.

 

Verifying Your Password

Now that we are able to generate a hash from our password, the question comes as to how we verify this. Using an MD5 or SHA1 password, you would have to know the SALT that was used to create the password, and you could simply test against that password. With this new method, things are slightly different. All we need is the hash, and a method to test it with, which PHP provides. This can be seen below:

 

$hash = '$1$toHVx1uW$KIvW9yGZZSU/1YOidHeqJ/';

if (password_verify('mypassword', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}

// Output: Password is valid! 

 

And there we have it. PHP has given us a password hashing algorithm that can provide secure passwords with very little effort. Take it from me, when I started developing in PHP the only way to get secure passwords was to use extensive and slow libraries and classes. Today, we have this built into PHP, and the PHP world is a better place.

 

Comment and Contribute

Your comment has been submitted and is pending approval.

Author:
Marc Plotz

Comment:



Comment:

(Maximum characters: 1200). You have characters left.