How to compare password hashes in PHP? posted May 2015
The wierdness of ==
Do you know what happens when you run this code in PHP?
<?php
var_dump(md5('240610708') == md5('QNKCDZO'));
var_dump(md5('aabg7XSs') == md5('aabC9RqS'));
var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));
var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));
var_dump('0010e2' == '1e3');
var_dump('0x1234Ab' == '1193131');
var_dump('0xABCdef' == ' 0xABCdef');
?>
Check the answer here. That's right, everything is True.
This is because ==
doesn't check for type, if a string looks like an integer it will first try to convert it to an integer first and then compare it.
More about PHP == operator here
This is weird and you should use ===
instead.
Even better, you can use hash_equals (coupled with crypt
)
Compares two strings using the same time whether they're equal or not.
This function should be used to mitigate timing attacks; for instance, when testing crypt() password hashes.
Here's the example from php.net:
<?php
$expected = crypt('12345', '$2a$07$usesomesillystringforsalt$');
$correct = crypt('12345', '$2a$07$usesomesillystringforsalt$');
$incorrect = crypt('apple', '$2a$07$usesomesillystringforsalt$');
hash_equals($expected, $correct);
?>
Which will return True
.
But why?
the hashed strings start with 0e
, for example both strings are equals in php:
md5('240610708') = 0e462097431906509019562988736854
md5('QNKCDZO') = 0e830400451993494058024219903391
because php understands them as both being zero to the power something big. So zero.
Security
Now, if you're comparing unencrypted or unhashed strings and one of them is supposed to be secret, you might have potentialy created the setup for a timing-attack.
Always try to compare hashes instead of the plaintext!
Comments
Robert
Good job, merci!
Michal Špa?ek
Thanks for sharing, if you're interested in more of these "collisions" check out https://github.com/spaze/hashes – it includes all the hashes I've generated so far including these you've used.
david
cool page michal!
Fedge
Still can't find the advantage over === anywhere, other than explicitly raising people's awareness of how poorly == works for certain things.
leave a comment...