I\'m using crypt()
to hash passwords in PHP, and am trying to work out the safest way of testing equality of the resulting hash when performing password checks.
When it comes to security I prefer to use the ===
operator. ===
ensures the two operands are exactly the same, without trying to accomodate some casting in order to "help" the comparison to reach a successful match - as it may help while developing thanks to a loose-typed language, like PHP.
Of course, one of the operand is to be trusted. A hash from the database is trustable, while the user input is not.
One can always dither for a while, coming to the conclusion there is no risk using ==
in a specific case. Maybe. But for instance
"0afd9f7b678fdefca" == 0 is true
"aafd9f7b678fdefca" == 0 is also true
as PHP tries to convert the "hash" into a number (probably using atoi) which gives 0. While it is unlikely crypt
returns 0, I'd prefer to maximize the cases where the passwords don't match (and answer a support call) by using ===
, than allowing a rare case that I didn't think about by using ==
.
As for strcmp
, the function returns <0
or >0
if different, and 0 if equal. But
strcmp("3", 0003) returns 0
strcmp("0003", 0003) returns -3
which are not surprising after all. A literal 0003
is actually an integer, 3
and since strcmp expects a string, the 3
will be converted to "3"
. But that shows there is some conversion that may happen in this case, since strcmp is a function, while ===
is part of the language.
So my preference in that case goes to ===
(which is faster than ==
anyway).
That is incorrect, please look at the definition of the function. According to PHP:
Returns < 0 if str1 is less than str2;
> 0 if str1 is greater than str2,
and 0 if they are equal
It returns less than 0 if str1 is less than str2. Note the phrase "less than", it does not return just -1, but any negative value. The same happens when str1 is greater than str2, but it returns a positive, non-zero value. It returns a positive value that can be 1, or any number thereafter.
strcmp()
returns a number that is the difference between the two strings starting with the last character that was found to be similar.
Here is an example:
$output = strcmp("red", "blue");
The variable $output with contain a value of 16
I think that using ==
would be sufficient in your case.
==
checks for equality regardless of type, whereas ===
checks for equality as well as type.
1 == "1"
= True
1 === "1"
= False
Since we're not too concerned with type, I'd keep it simple and go with ==
.
You should be using the hash_equals() function that is built into PHP. There would be no need to make your own function. The hash_equals() will return a boolean value.
In my opinion it is usually NOT a good idea to use == or === for comparing strings let alone hashed strings.