Приколы с алгоритмом Bcrypt для создания хешей

Автор:

LastTeamLead

5 января 2026

Всем известно, что пароли ни в коем случае нельзя хранить в открытом виде. Перед сохранением в БД или куда-либо еще данные хешируются алгоритмами, которые работают только в одну сторону – можно создать хеш из данных, но обратно получить оригинал не получится. Расшифровать хеш нельзя, можно только подобрать перебором. Иногда хеши могут даже совпадать на разных исходных данных, но в любом случае время на «взлом» хеша требуется очень большое, и это не гарантирует получение оригинальных данных.

Для хеширования существует много разных алгоритмов, и каждый имеет свои особенности, длину и структуру результата. Самые популярные алгоритмы – это SHA-256, SHA-1, MD5 и Bcrypt. За годы разработки я сталкивался со многими, но с Bcrypt почему-то дел особо не имел, хотя он используется во многих языках программирования, в том числе и в PHP. И на одном из CTF судьба свела с этим алгоритмом – это было весьма полезно, особенно в связке с PHP. Одна особенность может создать проблемы в безопасности.

Приколы с алгоритмом Bcrypt для создания хешей

По задачке была форма и код части бэкенда авторизации. Приведу только самую интересную часть, ее будет достаточно для понимания:

<?php
// соль
$entropy = "additional-entropy-for-super-secure-passwords-you-will-never-guess";
$login = 'admin';
// пароль не известен, он в недоступном конфиге 
$adminPass = getEnv('admin_password');

// настоящий хеш
$hashAuth = password_hash($username . $entropy . $adminPass, PASSWORD_BCRYPT);

// проверка данных из формы авторизации на соответствие хешу
if(password_verify(($_POST['user'] . $entropy . $_POST['pass']), $hashAuth)){
    // успешная авторизация
}

Известен хеш, соль пароля и логин админа. Сам пароль недоступен. Нужно пройти авторизацию.

Если посмотреть документацию PHP по методу password_hash, который использует Bcrypt для хеширования, то там есть предупреждение: использование алгоритма PASSWORD_BCRYPT приведёт к обрезанию поля password до максимальной длины – 72 байта. То есть для создания хеша используется только начало строки, если она больше 72 символов.

После этого предупреждения уязвимость сразу становится понятной – хеш формируется на основе «склеенных» в строку логина, соли и пароля. Но соль здесь длинная – 66 символов, логин – 5 символов, это уже 71 байт. Под сам пароль остается всего один символ. Все, что остается – проверить 95 вариантов (печатные ASCII-коды от 32 до 126) и подобрать первый символ пароля. Можно даже руками все варианты перебрать.

<?php
$hash = '$2y$10$Jkl13nDRnEiEe2t.NiUzaeZsyuTCFXn8Nmsfho4TixdEmFFfJITDq';

// Длина соли 66 символоы
$entropy = "additional-entropy-for-super-secure-passwords-you-will-never-guess";

// логин длинною 5 символов
$login = 'admin';

// длина хешируемой части строки - 72, 
// но соль + логин уже заняли 71 символ

// оба пароля будут валидные,
// т.к используется лишь первый символ - a
$realPassword = 'abcdef';
$fakePassword = 'a111222';

$hashAuth = password_hash($login . $entropy . $realPassword, PASSWORD_BCRYPT);

var_dump(password_verify(($login . $entropy . $realPassword), $hashAuth));
var_dump(password_verify(($login . $entropy . $fakePassword), $hashAuth));

Код с выводом результатов и хешей можно запустить онлайн тут: ссылка.

Если вы нашли опечатку или ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter

Также по теме:

Небезопасный кеш данных

/Код-ревью

Небезопасный кеш данных

Кеширование данных – штука полезная для скорости работы и оптимизации. Но часто кеш преподносит сюрпризы, если с ним напортачить или что-то не предусмотреть.
Прочитать

523