Атака по словарю основана на предположении, что пользователи выбирают
предсказуемые пароли. Вместо перебора всех возможных комбинаций
злоумышленник использует заранее подготовленный список распространённых
паролей: «123456», «password», «qwerty», имена, даты рождения и т.д.
Алгоритм атаки прост:
- Берётся список вероятных паролей
- Каждый пароль хэшируется тем же алгоритмом, что используется в
системе
- Полученный хэш сравнивается с хранимым в базе
- При совпадении пароль считается найденным
Эффективность такой атаки напрямую зависит от скорости хэширования.
Чем быстрее алгоритм, тем больше попыток можно выполнить за единицу
времени.
Радужные таблицы (Rainbow
Tables)
Радужные таблицы — это оптимизация атак по словарю, позволяющая не
вычислять хэш на лету, а использовать заранее подготовленные данные.
Суть:
- заранее вычисляются хэши для огромного числа паролей
- результаты сохраняются в виде таблиц
- при атаке происходит поиск совпадения хэша в таблице вместо
вычисления
Особенности:
- экономия времени за счёт увеличения объёма памяти
- возможность мгновенного подбора пароля для популярных хэшей
- особенно эффективны против быстрых хэш-функций (например, MD5,
SHA-1)
Главная уязвимость таких таблиц — одинаковые входные данные дают
одинаковый хэш. Это позволяет переиспользовать результаты.
Проблема быстрых хэш-функций
Классические криптографические функции (MD5, SHA-1, SHA-256):
- создавались для целостности данных, а не для защиты паролей
- работают максимально быстро
- легко масштабируются на GPU и специализированных устройствах
Это делает их крайне уязвимыми:
- миллиарды хэшей в секунду
- эффективное использование радужных таблиц
- дешёвое масштабирование атак
Основные механизмы защиты в
bcrypt
Библиотека bcrypt.js реализует алгоритм bcrypt, разработанный
специально для хранения паролей. Его устойчивость к атакам
обеспечивается тремя ключевыми механизмами:
1. Соль (Salt)
Соль — это случайная строка, добавляемая к паролю перед
хэшированием.
Пример:
password + random_salt → hash
Свойства:
- уникальна для каждого пароля
- хранится вместе с хэшем
- делает одинаковые пароли различными на уровне хэша
Почему это важно:
- радужные таблицы становятся бесполезными
- для каждой соли требуется отдельная таблица
- объём необходимых данных становится астрономическим
2. Медленный алгоритм
bcrypt специально сделан медленным и ресурсоёмким.
Ключевой параметр — cost factor (work factor):
2^cost операций хэширования
Пример:
const bcrypt = require('bcryptjs');
const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync('password', salt);
Где 10 означает:
- 2¹⁰ = 1024 итерации
- увеличение на 1 удваивает время вычисления
Эффект:
- атаки по словарю замедляются экспоненциально
- даже при использовании GPU скорость резко падает
- стоимость атаки становится экономически невыгодной
3. Адаптивность
bcrypt позволяет увеличивать сложность со временем:
- рост вычислительных мощностей → увеличение cost
- старые хэши можно пересчитывать при входе пользователя
Это делает алгоритм «долгоживущим» и устойчивым к прогрессу
железа.
Почему bcrypt
защищает от атак по словарю
При использовании bcrypt атака по словарю сталкивается с несколькими
препятствиями:
1. Отсутствие переиспользования результатов
- каждая соль уникальна
- один и тот же пароль даёт разные хэши
- нельзя заранее вычислить универсальный словарь
2. Высокая стоимость каждой попытки
- каждый пароль требует отдельного вычисления
- операция дорогая по времени
- массовый перебор становится медленным
3. Ограниченная масштабируемость
- bcrypt плохо распараллеливается
- GPU не даёт такого прироста, как для SHA
- атака требует больше ресурсов
Почему
радужные таблицы не работают против bcrypt
Для эффективной работы радужных таблиц нужны:
- детерминированность (одинаковый вход → одинаковый выход)
- отсутствие случайности
- быстрые вычисления
bcrypt нарушает все три условия:
| Свойство |
bcrypt |
| Детерминированность |
Нет (из-за соли) |
| Повторяемость |
Нет |
| Скорость |
Низкая |
Следствие:
- таблицы нужно строить для каждой соли отдельно
- объём данных становится неподъёмным
- вычисления слишком медленные для массовой генерации
Практический пример атаки
Без bcrypt (например,
SHA-256):
- 1 миллиард хэшей/сек
- словарь: 10 млн паролей
- время: доли секунды
С bcrypt (cost = 10):
- ~100 хэшей/сек
- словарь: 10 млн
- время: более суток
С bcrypt (cost = 12):
- ~25 хэшей/сек
- время: недели
Рост сложности делает атаку практически бессмысленной.
Структура bcrypt-хэша
bcrypt хранит всю необходимую информацию в строке:
$2a$10$E9N6n5...rest_of_hash
Расшифровка:
$2a$ — версия алгоритма
10 — cost factor
- далее — соль + хэш
Это позволяет:
- автоматически извлекать параметры
- корректно проверять пароль без внешних данных
Проверка пароля
bcrypt не сравнивает строки напрямую. Он повторно хэширует ввод
пользователя с теми же параметрами:
bcrypt.compareSync('input_password', stored_hash);
Внутри:
- извлекается соль и cost
- выполняется хэширование
- сравниваются результаты
Ограничения и важные нюансы
Несмотря на устойчивость, bcrypt не является абсолютной защитой:
- слабые пароли всё равно подбираются
- утечка базы даёт возможность офлайн-атак
- низкий cost снижает безопасность
Рекомендуемые практики:
- использовать cost не ниже 10–12
- применять ограничения на попытки входа
- внедрять двухфакторную аутентификацию
- проверять сложность паролей
Сравнение с другими
подходами
| Метод |
Устойчивость к словарю |
Устойчивость к rainbow tables |
| MD5 |
Низкая |
Нет |
| SHA-256 |
Низкая |
Нет |
| bcrypt |
Высокая |
Полная |
| scrypt |
Очень высокая |
Полная |
| Argon2 |
Очень высокая |
Полная |
bcrypt остаётся популярным благодаря:
- простоте
- проверенной надёжности
- широкой поддержке
Ключевая идея защиты
bcrypt не делает подбор невозможным — он делает его
невыгодным:
- по времени
- по ресурсам
- по стоимости
Именно это превращает атаки по словарю и радужные таблицы из
практического инструмента в теоретическую возможность.