I'm implementing a CSRF protection system for my website (forms) and I've noticed a strange (?) thing using hash_equals + crypt. An example to explain it (PHP 8.1.8):
$sessionToken = crypt(“562710df09d5b3b1e33769cd50a7e15d0cad770e66771ebbe9”, ‘12345');
$postToken = crypt(“562710df09d5b3b1e33769cd50a7e15d0cad770e66771ebbe9”, ‘12345');
$res = hash_equals($sessionToken, $postToken);
var_export($res); // true (right)
$postToken = crypt(“562710df09d5b3b1e33769cd50a7e15d0cad770e66771ebbe8”, ‘12345'); // HERE I'VE CHANGED THE LAST CHARACTER (8 instead of 9)
$res = hash_equals($sessionToken, $postToken);
var_export($res); // true (while it should be false)
This doesn't happen if what you change is the first character of $postToken (it returns false), or if you don't use crypt in hash comparison (I've tried it).
Is it normal?
What I have tried:
$sessionToken = crypt(“562710df09d5b3b1e33769cd50a7e15d0cad770e66771ebbe9”, ‘12345');
$postToken = crypt(“562710df09d5b3b1e33769cd50a7e15d0cad770e66771ebbe9”, ‘12345');
$res = hash_equals($sessionToken, $postToken);
var_export($res); // true
$postToken = crypt(“562710df09d5b3b1e33769cd50a7e15d0cad770e66771ebbe8”, ‘12345');
$res = hash_equals($sessionToken, $postToken);
var_export($res); // true