What's wrong with md5($_GET['password'])?

ยท

4 min read

What's wrong with md5($_GET['password'])?

Storing your users' passwords securely is critical.

But still, you can find code like $hash=md5($_GET['password']) in many code bases.

So, what's wrong about it?

Using md5 to hash passwords

While it's good to see use of a hash in the code - instead of storing the password in plain text - md5 is not a good choice (anymore) because "The security of the MD5 hash function is severely compromised".

No "salt"

What makes things worse is not using any kind of salt but just the password as input to the hash.

This makes the code vulnerable to rainbow table attacks. "Rainbow tables" are pre-computed tables mapping a hash to its original input. So, if you know a hash of password, you can lookup the original string very quickly without any computation!

At least for common passwords without salt (or very simple salt).

So, to better protect the code against such an attack, at least this code would be better (still not good!):

$pw=md5($_GET['password'] . 'myHardToGuessHashSalt').

This way, one would need to have a rainbow table of all passwords, but with myHardToGuessHashSalt appended to each of them. It's way less likely someone ever pre-computed such a table and would have to compute such a rainbow table before starting attacking you.

To make attacks even harder, you can create a random password for each single password you store and save it along the hash. This way, an attacker would need to create a rainbow table for each single password, which essentially requires the same computation time as a brute-force attack anyway.

Using $_GET['password']

This requires you to send the password from the browser to your server via a GET rather than a POST request. While this not really is a problem when using HTTPS, still GET parameters are much more prone to end up in browser histories or server logs - revealing the sent password in plain text.

Solution: Use a proper hash algorithm with salt

Fortunately, all the aforementioned problems are already solved for you: just use password_hash function to hash your passwords.

It lets you choose a solid, proven hash algorithm like bcrypt (or defaults to a good one) and automatically creates a random, strong salt for your hashed password.

So, this is how you properly hash a password in PHP:

  1. When prompting the user for their password while creating an account, send the password via a POST request.
  2. Use password_hash to properly hash the password and store the returned hash string in your database.
  3. When the user tries to log in later, again, send the input password via a POST request.
  4. Use `password_verify' to check the password. Just pass in the password the user entered and the user's password hash retrieved from your database.