Использование MD5 и SHA-256 для хранения паролей встречается в старых системах и до сих пор повторяется в учебных примерах, что создаёт опасную иллюзию допустимости такого подхода. Оба алгоритма относятся к криптографическим хэш-функциям общего назначения, но не предназначены для защиты паролей.
Ключевая проблема заключается не в математической слабости самих алгоритмов в классическом смысле, а в их скорости. Они вычисляются слишком быстро, что делает их идеальной целью для перебора.
Криптографические хэш-функции (MD5, SHA-1, SHA-256) создавались для:
Требования к ним:
Но для паролей требуется противоположное:
Хэширование паролей — это не просто “перевод строки в фиксированный набор байт”, а специально усложнённый процесс защиты от атак перебором.
MD5 сегодня не рекомендуется использовать ни в каком криптографическом контексте, связанном с безопасностью.
Основные проблемы:
Любой пароль, обработанный MD5, может быть восстановлен за короткое время с использованием готовых баз.
SHA-256 считается криптографически стойким алгоритмом, но это не делает его подходящим для паролей.
Основная ошибка использования SHA-256 для паролей:
Пример уязвимости:
SHA-256 защищает данные от изменения, но не защищает от перебора.
Для MD5 и SHA-256 существуют огромные базы предвычисленных хэшей.
Суть атаки:
Без соли такие атаки работают практически мгновенно.
Современные видеокарты и специализированные устройства позволяют:
Алгоритмы вроде SHA-256 не ограничивают скорость атакующего, что делает их непригодными для защиты паролей.
Соль — это случайная строка, добавляемая к паролю перед хэшированием.
Пример:
hash = SHA256(password + salt)
Назначение соли:
Но даже с солью SHA-256 остаётся слишком быстрым, что не решает проблему полностью.
Библиотека bcrypt.js реализует алгоритм bcrypt — специально разработанный для хранения паролей.
Ключевые свойства bcrypt:
bcrypt основан на алгоритме Blowfish и использует многократное “растягивание” ключа.
bcrypt выполняет следующие шаги:
Важный параметр — cost factor:
2^cost = количество раундов
Чем выше cost, тем медленнее вычисление и тем выше безопасность.
npm install bcryptjs
const bcrypt = require('bcryptjs');
const password = 'user_password';
const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync(password, salt);
console.log(hash);
Автоматическая генерация соли:
const hash = bcrypt.hashSync(password, 10);
const isValid = bcrypt.compareSync('user_password', hash);
console.log(isValid); // true или false
bcrypt автоматически извлекает соль из хэша и использует её при проверке.
Синхронные методы блокируют поток выполнения, что критично в серверных приложениях.
Асинхронный вариант:
const bcrypt = require('bcryptjs');
bcrypt.hash('password', 10, (err, hash) => {
if (err) throw err;
bcrypt.compare('password', hash, (err, result) => {
console.log(result);
});
});
Типичные значения:
Рост cost увеличивает время вычисления экспоненциально.
Снижение cost ради производительности приводит к ослаблению защиты.
Любые “ускорения” через хранение plaintext-паролей полностью уничтожают безопасность системы.
bcrypt уже включает соль. Внешнее управление солью нарушает модель безопасности.
if (hash === userInputHash)
Такой подход не работает, так как bcrypt включает случайные элементы.
Сравнение характеристик:
Главное отличие bcrypt — контроль времени вычисления, а не только криптографическая стойкость.
SHA-256 остаётся полезным для:
Но не для хранения паролей.
Правильный подход:
Использование MD5 или SHA-256 в этой модели является архитектурной ошибкой, приводящей к компрометации системы при утечке базы данных.