
Волшебные хэши – PHP-хэш «коллизии»
Зарегистрируйтесь с паролем 1, а затем войдите с паролем 2. Если вы вошли, значит, хранилище использует указанный алгоритм для хеширования пароля, а PHP сравнивает их с помощью == (для MD5, SHA-1 и обычного текста).
Для MD5, SHA-1 и семейства SHA-2 используется давно известный трюк (на самом деле это документированная особенность, см. Таблицы сравнения типов PHP и Числа с плавающей запятой): для PHP '0e1' == '00e2' == '0', просто применяется это в практических целях. Любой пароль совпадает с любым другим паролем из списка. Это иной трюк, нежели целочисленные строки, переполняющиеся в числа с плавающей запятой, просто посмотрите на разницу между этими двумя строками.
Это все алгоритмы с magic-хешами:
md5(md5(password))Если процитировать @0xb0bb, «у magic-хешей есть и другие применения, помимо сравнения паролей (например, слои кэширования или данные, производные от вывода хеш-функции), где эти известные небезопасные, малоизвестные и псевдохеш-алгоритмы можно встретить чаще».
Для обычного текста используются различные трюки с преобразованием. Первый пароль будет совпадать только со вторым. Трюки сгруппированы по версиям PHP, в которых они работают.
bcrypt усекает пароли до максимальной длины 72 символов. Пароли совпадают, если первые 72 символа обоих паролей совпадают.
descrypt (традиционный UNIX DES crypt) усекает пароли до максимальной длины 8 символов. Пароли также совпадают, если первые 8 символов обоих паролей совпадают, см. раздел «Общая перекрёстная проверка».
Если вы используете пароль длиннее 64 байт и хешируете его с помощью PBKDF2-HMAC-SHA1, он сначала предварительно хешируется с помощью SHA1, поэтому PBKDF2-HMAC-SHA1(password1) === PBKDF2-HMAC-SHA1(password2), потому что sha1(password1) === bin2hex(password2). Аналогичное предварительное хеширование применяется для PBKDF2-HMAC-SHA224 и PBKDF2-HMAC-SHA256.
Сейчас в каждом из них есть лишь один magic-хеш благодаря Norbert Tihanyi, в будущем, надеюсь, их добавится больше.
Используйте === при сравнении чего-либо* в PHP, а не ==. И используйте password_hash() и password_verify() для хеширования паролей в PHP, не используйте MD5 или SHA-1. *Используйте hash_equals() при сравнении хешей.
Всё началось с этого твита. Я сгенерировал QNKCDZO и 240610708 в феврале 2014 года, и с тех пор это распространилось по всему интернету. Просто загуглите.