bcrypt для хеширования паролей Почему исключительно шифрование недостаточно
Если вы храните пароли пользователей с помощью AES, RSA или даже SHA-256, вы делаете это неправильно. Не просто немного неправильно — фундаментально неправильно. Это самый распространённый ошибка в разработке веб-приложений, и у неё есть простое решение: используйте специализированную функцию хеширования паролей, например, bcrypt.
Вот почему это важно, как работает bcrypt и как выглядит готовый код для производства.
Почему пароли требуют особых мер
Большинство криптографических операций разработаны таким образом, чтобы быть обратимыми или быстрыми. Шифрование по умолчанию обратимо — это его основная цель. SHA-256 и MD5 работают быстро, обрабатывают гигабайты в секунду. Оба этих свойства катастрофичны для паролей.
Когда атакующий получает вашу базу данных, он получает хеши паролей. При шифровании, если они находят ключ, они могут расшифровать всё. При быстрых хешированиях, таких как MD5 или SHA-256, они запускают атаку с использованием GPU — современное оборудование может проверять сотни миллиардов хешей MD5 в секунду. Ваш «сложный» пароль может быть взломан за минуты.
Пароли должны быть:
- необратимыми — даже при наличии ключа или алгоритма, вы не можете получить исходный текст
- медленными при вычислении — намеренная медленность делает атаки брутфорсом нецелесообразными
- уникальными для каждого пользователя — одинаковые пароли должны генерировать разные хеши
bcrypt удовлетворяет всем трём условиям. Общие функции хеширования и шифрования не удовлетворяют этим требованиям.
Хеширование против шифрования против хеширования паролей
Это не взаимозаменяемо:
| Подход | Обратимый? | Быстрый? | Безопасен для паролей? |
|---|---|---|---|
| Шифрование (AES, RSA) | Да — при наличии ключа | Да | Нет |
| Быстрые хеши (MD5, SHA-256) | Нет | Да (по дизайну) | Нет |
| Хеширование паролей (bcrypt, Argon2id) | Нет | Нет (по дизайну) | Да |
Обратимость шифрования — это критическая ошибка: если утечка ключа, то утечка всех паролей. Быстрое хеширование — это критическая ошибка: скорость позволяет проводить брутфорс. Функции хеширования паролей разработаны специально для медленного выполнения — и это их цель.
Как работает bcrypt
bcrypt, разработанный в 1999 году Найлем Проевсом и Дэвидом Мазиерсом, делает три вещи, которые важны:
1. Применение соли. Перед хешированием bcrypt генерирует случайную соль (16 байт) и включает её в выход хеширования. Даже если два пользователя используют одинаковый пароль, их хеши будут разными. Это полностью устраняет атаки с предварительно вычисленными таблицами.
2. Параметр нагрузки (стоимость). bcrypt принимает параметр стоимости (обычно 10–14). Каждое увеличение удваивает время вычислений. При стоимости 12 хеширование занимает примерно 250–400 мс на современном оборудовании. Это незаметно медленно для запроса входа — но делает брутфорс с миллиардами попыток операцией, которая занимает десятилетия.
3. Выход является самосодержащим. Хеш bcrypt выглядит так $2b$12$... и включает в себя версию алгоритма, фактор нагрузки, соль и хеш. Вам не нужно отдельное поле соль. Храните всю строку.
Готовый код: Node.js и Python
Node.js (bcryptjs или bcrypt)
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12;
// Hash a password
async function hashPassword(plaintext) {
return bcrypt.hash(plaintext, SALT_ROUNDS);
}
// Verify a password against a stored hash
async function verifyPassword(plaintext, storedHash) {
return bcrypt.compare(plaintext, storedHash);
}
// Usage
const hash = await hashPassword('hunter2');
// Store `hash` in your database
const isValid = await verifyPassword('hunter2', hash);
// true
Python (bcrypt)
import bcrypt
COST = 12
def hash_password(plaintext: str) -> bytes:
salt = bcrypt.gensalt(rounds=COST)
return bcrypt.hashpw(plaintext.encode('utf-8'), salt)
def verify_password(plaintext: str, stored_hash: bytes) -> bool:
return bcrypt.checkpw(plaintext.encode('utf-8'), stored_hash)
# Usage
hashed = hash_password('hunter2')
# Store hashed in your database
is_valid = verify_password('hunter2', hashed)
# True
Храните полную строку хеша. Никогда не храните исходный текст, никогда не храните соль отдельно, никогда не храните промежуточные значения.
Выбор фактора нагрузки
Правильный фактор нагрузки зависит от вашего оборудования. Цель — чтобы каждая операция хеширования занимала 200–500 мс на вашем сервере в производстве. Это достаточно быстро для хорошего пользовательского опыта, медленно для атакующих.
Текущий рекомендации: стоимость 12 как минимум, 14 для высокозначимых аккаунтов (администраторы, финансовые). Проведите тест на вашем реальном оборудовании:
// Node.js: benchmark different cost factors
const bcrypt = require('bcrypt');
for (let cost = 10; cost <= 14; cost++) {
const start = Date.now();
await bcrypt.hash('benchmark', cost);
console.log(`Cost ${cost}: ${Date.now() - start}ms`);
}
Если стоимость 12 занимает менее 100 мс, увеличьте её. Если стоимость 14 занимает более 1000 мс, снизьте до 13. Повторяйте раз в год — оборудование становится быстрее, и ваш фактор стоимости должен соответствовать этому.
Вы можете протестировать хеширование bcrypt интерактивно с помощью IO Tools генератора хешей bcrypt.
bcrypt против Argon2id против scrypt
bcrypt проверен и широко поддерживается. Но у него есть ограничение: он не является память-нагруженным. Атакующий с специализированным оборудованием (ASIC или FPGA) может параллельно проводить атаки более эффективно, чем при использовании память-нагруженных альтернатив.
| Алгоритм | Память-нагруженный | Сопротивление параллелизму | Рекомендация |
|---|---|---|---|
| bcrypt | Нет | Частичный | Хороший стандарт; используйте стоимость ≥12 |
| scrypt | Да | Частичный | Лучше, чем bcrypt, меньше инструментов |
| Argon2id | Да | Да | Рекомендуется для новых проектов |
Для новых проектов: используйте Argon2id. Он победил в соревновании по хешированию паролей (2015), является память-нагруженным, сопротивляется атакам GPU и ASIC и сейчас рекомендуется OWASP. Интерфейс почти идентичен bcrypt.
Для существующих проектов: если вы уже используете bcrypt с разумным фактором стоимости, миграция не является срочной. Добавьте это в ваш следующий крупный переписывание.
Частые ошибки при реализации
Хеширование хеша. Некоторые разработчики хешируют пароль на клиенте перед отправкой, а затем хешируют его снова на сервере. Клиентский хеш становится «паролем». Теперь вы хешируете фиксированную строку из шестнадцатеричных цифр, а не пароль, который выбрал пользователь — вы теряете ничего от двойного хеширования, но вы получаете ничего и вводите путаницу.
Проблема 72-байтового ограничения. bcrypt тихо игнорирует всё, что превышает 72 байта. Пароль из 100 символов и пароль из 72 символов, которые совпадают в первых 72 символах, считаются одинаковыми в bcrypt. Если пользователи устанавливают очень длинные пароли, это приводит к неявному снижению безопасности. Мера: предварительно хешируйте с помощью SHA-256 перед передачей в bcrypt — но только если вы полностью понимаете последствия и документируете это явно.
Слабый фактор нагрузки. Фактор 10 был приемлем в 2011 году. В 2026 году используйте как минимум 12. Если ваши существующие записи используют фактор 10, вы можете обновить их прозрачно: после успешного входа, перехешируйте подтверждённый пароль с новым фактором и сохраните обновлённый хеш.
Асинхронность имеет значение. bcrypt — это CPU-нагруженный процесс. Всегда используйте асинхронный API (как показано выше) в Node.js, чтобы избежать блокировки event loop. Синхронный bcrypt в сервере Node.js сделает каждый другой запрос ждать.
Миграция с MD5/SHA на bcrypt
Вы не можете перехешировать без исходного текста. Но вы можете мигрировать с оптимизацией:
- Добавьте
password_hashстолбец рядом с старымpassword_md5столбец - При успешном входе (когда у вас есть исходный текст), хешируйте его с помощью bcrypt и сохраняйте в
password_hash, удаляйте старый столбец - После периода миграции пользователи, которые не входили, могут быть вынуждены сбросить пароль
- Один раз
password_md5будет пустым для всех пользователей, удалите столбец
Это стандартный подход и требует нулевого времени остановки.
Суть
Шифрование предназначено для данных, которые нужно получить. Хеширование предназначено для данных, которые нужно проверить. Пароли должны проверяться, а не извлекаться — это означает, что шифрование — неподходящий инструмент.
bcrypt даёт вам соль, настраиваемую медленность и самосодержащий формат хеша. Это правильный ответ уже 25 лет. Используйте его с фактором нагрузки 12 или выше, используйте Argon2id для новых проектов и мигрируйте с MD5 и SHA-256 как можно скорее.
Ошибки в этом не являются гипотетическими рисками. Базы данных уязвимы. Когда они уязвимы, правильно хешированные пароли практически невозможно взломать. Хеши MD5 могут быть взломаны за ночь.
Вам также может понравиться
Установите наши расширения
Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска
恵 Табло результатов прибыло!
Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!
Подписаться на новости
все Новые поступления
всеОбновлять: Наш последний инструмент был добавлен 16 мая 2026 года
