Структура bcrypt-хеша: версия, cost factor, соль, хеш

bcrypt-хеш представляет собой строку фиксированного формата, в которой закодированы все параметры, необходимые для проверки пароля. В отличие от многих других алгоритмов, bcrypt не хранит отдельно соль или параметры — всё включено непосредственно в итоговую строку.

Структура bcrypt-хеша выглядит следующим образом:

$<версия>$<cost>$<соль><хеш>

Пример:

$2b$10$eImiTXuWVxfM37uY4JANjQ==qP5Zp7yZ3GQ8WZx7h1Y5s9X5FhQhW

Каждая часть строки имеет строго определённое назначение.


Версия алгоритма

Первая часть строки определяет версию bcrypt:

$2a$, $2b$, $2y$

Наиболее распространённые варианты:

  • 2a — оригинальная версия bcrypt
  • 2b — исправленная версия с устранёнными уязвимостями
  • 2y — вариант, используемый в некоторых системах (например, PHP)

В контексте bcrypt.js чаще всего используется версия 2a или 2b. Различия между ними касаются внутренних исправлений и совместимости, но для практического использования это прозрачно — библиотека сама корректно обрабатывает нужную версию.


Cost factor (work factor)

Следующий компонент — это параметр сложности:

$2b$10$

Число 10 — это cost factor (или work factor). Он определяет, сколько раз будет выполняться алгоритм хеширования.

Фактически это степень двойки:

количество итераций = 2^cost

Примеры:

  • cost = 10 → 1024 итерации
  • cost = 12 → 4096 итераций
  • cost = 14 → 16384 итерации

Чем выше значение:

  • тем медленнее вычисляется хеш
  • тем сложнее перебор (brute-force)

Особенности:

  • значение обычно находится в диапазоне 8–14
  • увеличение на 1 удваивает время вычисления
  • bcrypt изначально разработан как медленный алгоритм, чтобы противостоять атакам

Соль (salt)

Следующая часть — это соль:

eImiTXuWVxfM37uY4JANjQ==

Особенности соли в bcrypt:

  • длина: 16 байт
  • кодируется в Base64 (специальная вариация bcrypt Base64)
  • генерируется случайным образом при каждом хешировании

Назначение соли:

  • предотвращение атак с использованием радужных таблиц
  • обеспечение уникальности хеша даже при одинаковых паролях

Пример:

password123 → разные соли → разные хеши

bcrypt автоматически генерирует соль, поэтому вручную управлять ей обычно не требуется.


Хешированное значение

После соли следует непосредственно результат хеширования:

qP5Zp7yZ3GQ8WZx7h1Y5s9X5FhQhW

Особенности:

  • длина: 24 байта (192 бита)

  • также кодируется в Base64

  • формируется на основе:

    • исходного пароля
    • соли
    • cost factor

Итоговый хеш всегда имеет фиксированную длину строки (~60 символов).


Полный разбор строки

Пример:

$2b$10$eImiTXuWVxfM37uY4JANjQ==qP5Zp7yZ3GQ8WZx7h1Y5s9X5FhQhW

Разделение:

Часть Значение
$2b$ версия алгоритма
10 cost factor
eImiTXuWVxfM37uY4JANjQ== соль (16 байт)
qP5Zp7yZ3GQ8WZx7h1Y5s9X5FhQhW хеш (24 байта)

Как bcrypt использует структуру при проверке пароля

При проверке пароля bcrypt:

  1. Извлекает из строки:

    • версию
    • cost factor
    • соль
  2. Повторно хеширует введённый пароль с этими параметрами

  3. Сравнивает полученный результат с сохранённым хешем

Ключевой момент:

  • соль не хранится отдельно
  • все параметры уже встроены в строку

Особенности кодирования

bcrypt использует модифицированный Base64, который отличается от стандартного:

  • используется другой набор символов
  • отсутствует padding =
  • строка всегда фиксированной длины

Это важно учитывать при ручной обработке строк — стандартные Base64-декодеры могут не подойти.


Почему структура bcrypt считается безопасной

  1. Встроенная соль

    • исключает повторяющиеся хеши
    • защищает от precomputed атак
  2. Настраиваемая сложность

    • позволяет адаптироваться к росту вычислительных мощностей
  3. Самодостаточность

    • вся информация хранится в одной строке
    • упрощает хранение и перенос данных
  4. Медленное вычисление

    • делает массовый перебор экономически невыгодным

Практическое использование в bcrypt.js

При вызове:

bcrypt.hash(password, 10)

происходит:

  1. Генерация случайной соли
  2. Применение cost factor = 10
  3. Формирование строки в формате bcrypt

Результат уже содержит:

  • версию
  • cost
  • соль
  • хеш

При проверке:

bcrypt.compare(password, hash)

библиотека:

  • автоматически извлекает параметры
  • повторяет вычисления
  • возвращает результат сравнения

Ограничения и нюансы

  • максимальная длина пароля: 72 байта
  • всё, что длиннее, игнорируется
  • рекомендуется дополнительно хешировать длинные строки (например, через SHA-256 перед bcrypt)

Визуальное представление структуры

| $2b$ | 10 | $ |     соль (22 символа)     |        хеш (31 символ)        |

Общая длина строки:

60 символов

Итоговое понимание структуры

bcrypt-хеш — это не просто результат хеширования, а контейнер, включающий:

  • алгоритмическую версию
  • параметры сложности
  • случайную соль
  • итоговый хеш

Такая структура делает bcrypt самодостаточным, переносимым и устойчивым к большинству распространённых атак на пароли.