У меня есть два док-контейнера, в одном PHP 8.2.3, в другом PHP 7.4.30.
Кроме того, у меня есть база данных с существующими хэшами паролей (которые были изначально созданы фреймворком Yii2 с использованием пароля password_hash в неизвестной среде).
Я сделал test.php, где вывел две вещи:
var_dump(password_get_info('$2a$07$6c2eb62b00df224f3d20$.qzdiDRZejMnGytXWsA7Jid7RpWazDc6'))
И
var_dump(password_verify('password', '$2a$07$6c2eb62b00df224f3d20$.qzdiDRZejMnGytXWsA7Jid7RpWazDc6'))
В PHP 7.4 результаты следующие:
array(3) {
["algo"]=>
NULL
["algoName"]=>
string(7) "unknown"
["options"]=>
array(0) {
}
}
И
bool(true)
В то время как в PHP 8.2:
array(3) {
["algo"]=>
NULL
["algoName"]=>
string(7) "unknown"
["options"]=>
array(0) {
}
}
И
bool(false)
Я знаю, что могли использоваться разные алгоритмы хеширования. Но алгоритм хеширования должен быть указан (и, следовательно, идентифицирован) в самом хеше.
Кроме того, оба двигателя не знают алгоритма. Однако PHP 7.4 может проверить пароль.
Почему это происходит?
Из документов:
Обратите внимание, что password_hash() возвращает алгоритм, стоимость и соль как часть возвращаемого хэша. Поэтому вся информация, необходимая для убедитесь, что хэш включен в него. Это позволяет функции проверки проверить хэш без необходимости отдельного хранения для соли или
Что за... о, большое спасибо. Это невероятно. Почему? Так как это минорная версия. Супер странно
Вероятно, конкретно связано с этим исправлением: bugs.php.net/bug.php?id=81744
Хотя я не могу найти фактическое изменение кода, связанное с этим, это единственное актуальное изменение в этих затронутых версиях: php.net/ChangeLog-8.php#8.2.3 , php.net/archive/ 2023.php#2023-02-14-3
На вас повлияло это исправление:
Неправильно отформатированные хэши BCrypt, которые содержат $ в своей солевой части, вызовут перезапись буфера и могут ошибочно признать действительным любой пароль. [..] «PHP Hack» существует с самой первой версии собственной crypt_blowfish реализации PHP, и в комментариях или истории коммитов не дается четкого объяснения его существования. В любом случае такой хэш не является действительным хэшем BCrypt и не генерируется password_hash(), который является рекомендуемым API хеширования паролей в PHP. Хотя технически это может нарушить обратную совместимость с существующими пользователями, тот факт, что эти хэши никогда не генерируются password_hash(), не принимаются другими реализациями BCrypt и представляют возможные уязвимости безопасности в приложениях, они должны быть отклонены во всех поддерживаемых версиях PHP. https://github.com/php/php-src/security/advisories/GHSA-7fj2-8x79-rjf4
Акцент здесь делается на том факте, что ваш хеш, по-видимому, технически недействителен с самого начала и никогда не должен был существовать.
Я помню, что более ранние версии password_hash() допускали использование соли пользователем. Так что держу пари, что здесь должно быть так.
Может и правда. До сих пор я узнал, что хэш был жестко запрограммирован при миграции базы данных, предполагая, что это хэш для «пароля». Но как был сгенерирован хеш - никто не знает. Хорошей новостью является то, что это только для среды разработки. Первый раз в жизни я натыкаюсь на ошибку после минорного обновления версии, прямо перед установкой нового контейнера докеров. До 14 февраля я бы не столкнулся с этим :)
@YourCommonSense Как автор этого совета: Нет, password_hash никогда не мог выдать искаженный хеш, даже с добавленной пользователем солью. В этом случае также легко увидеть, что хэш не был сгенерирован password_hash из-за префикса $2a$ вместо $2y$. Хеш, вероятно, был создан путем прямого вызова crypt().
FWIW, кажется, это ошибка конкретно в этой версии PHP (и двух других): 3v4l.org/aJlhb