Strcmp vs. == vs. === в PHP для проверки хэш-равенства
Я использую crypt()
для хэш-паролей в PHP и пытаюсь разработать самый безопасный способ проверки равенства полученного хэша при выполнении проверок пароля.
Есть три варианта, которые я могу видеть:
Вариант 1 - двойные равные
function checkPassword($hash, $password)
{
return crypt($password, $hash) == $hash;
}
Вариант 2 - Triple Equals
function checkPassword($hash, $password)
{
return crypt($password, $hash) === $hash;
}
Вариант 3 - strcmp()
function checkPassword($hash, $password)
{
return strcmp(crypt($password, $hash), $hash) === 0;
}
Моя интуиция подсказывает мне, что вариант 1 - плохая идея из-за отсутствия проверки типа, и что варианты 2 или 3, вероятно, будут лучше. Тем не менее, я не могу разобраться, если произойдет конкретный случай, когда ===
или strcmp
завершится сбой. Что безопаснее для этой цели?
Ответы
Ответ 1
Когда речь идет о безопасности, я предпочитаю использовать оператор ===
. ===
гарантирует, что два операнда будут точно такими же, не пытаясь приспособить кастинг, чтобы "помочь" сравнению для достижения успешного совпадения, поскольку это может помочь при разработке благодаря языку, на котором написана фраза, например PHP.
Конечно, одному из операндов нужно доверять. Хэш из базы данных является надежным, а пользовательский ввод не является.
Можно всегда сглазить какое-то время, придя к выводу, что в конкретном случае нет риска использовать ==
. Может быть. Но, например,
"0afd9f7b678fdefca" == 0 is true
"aafd9f7b678fdefca" == 0 is also true
поскольку PHP пытается преобразовать "хэш" в число (возможно, используя atoi), который дает 0. Хотя маловероятно, что crypt
возвращает 0, я бы предпочел максимизировать случаи, когда пароли не совпадают ( и ответьте на вызов поддержки), используя ===
, чем разрешить редкий случай, о котором я не думал, используя ==
.
Что касается strcmp
, функция возвращает <0
или >0
, если они разные, и 0, если они равны. Но
strcmp("3", 0003) returns 0
strcmp("0003", 0003) returns -3
что неудивительно в конце концов. Литерал 0003
на самом деле является целым числом, 3
, и поскольку strcmp ожидает строку, 3
будет преобразован в "3"
. Но это показывает, что в этом случае может произойти некоторое преобразование, поскольку strcmp является функцией, а ===
является частью языка.
Таким образом, мое предпочтение в этом случае переходит в ===
(что быстрее, чем ==
).
Ответ 2
Вы должны использовать функцию hash_equals(), встроенную в PHP. Не было бы необходимости создавать свою собственную функцию. Функция hash_equals() вернет логическое значение.
По-моему, обычно не рекомендуется использовать == или === для сравнения строк, не говоря уже о хэшированных строках.
Ответ 3
Это неверно, посмотрите на определение функции.
Согласно PHP:
Returns < 0 if str1 is less than str2;
> 0 if str1 is greater than str2,
and 0 if they are equal
Он возвращает меньше 0, если str1 меньше str2. Обратите внимание на фразу "меньше", она не возвращает только -1, но любое отрицательное значение. То же самое происходит, когда str1 больше str2, но возвращает положительное, ненулевое значение. Он возвращает положительное значение, которое может быть 1 или любое число после этого.
strcmp()
возвращает число, которое является разницей между двумя строками, начиная с последнего символа, который был найден похожим.
Вот пример:
$output = strcmp("red", "blue");
Вывод переменной $output содержит значение 16
Ответ 4
Я думаю, что использование ==
было бы достаточно в вашем случае.
==
проверяет равенство независимо от типа, тогда как ===
проверяет как равномерность, так и тип.
1 == "1"
= True
1 === "1"
= False
Поскольку мы не слишком озабочены типом, я бы сохранил его просто и перешел с ==
.