Пароль пользователя нельзя хранить в открытом виде и нельзя «шифровать» обратимым алгоритмом. База может утечь, и тогда все пароли окажутся под угрозой. Правильный подход — хранить необратимый хеш, по которому можно только проверить введённый пароль.
Почему не md5 и не sha1
Быстрые хеши вроде md5 и sha1 для паролей не подходят. Они проектировались для проверки целостности, а не для защиты секретов: современная видеокарта перебирает миллиарды вариантов в секунду. Соль спасает от радужных таблиц, но не от перебора.
bcrypt намеренно медленный. Внутри есть соль, а стоимость вычисления задаётся параметром cost. Увеличивая cost на единицу, вы примерно вдвое увеличиваете время проверки — и для пользователя, и для атакующего.
Как это выглядит в Laravel
Создание хеша при регистрации или смене пароля:
use Illuminate\Support\Facades\Hash;
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
Проверка при входе:
if (! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => 'Неверный пароль.',
]);
}
В колонке password лежит строка вида $2y$12$…. В ней зашиты алгоритм, cost и соль. Отдельное поле для соли не нужно.
Cost и производительность
По умолчанию Laravel использует bcrypt с cost 12. На обычном сервере одна проверка занимает десятки миллисекунд — это нормально. Если поставить cost 14–15, вход станет заметно медленнее, а нагрузка на CPU вырастет. Для большинства проектов 12 — разумный баланс.
Менять cost можно через BCRYPT_ROUNDS в .env или в config/hashing.php. Старые хеши продолжат работать: cost хранится внутри строки, а Laravel умеет перехешировать пароль при успешном входе, если параметры изменились.
Хеш вне Laravel
Иногда нужно создать пользователя напрямую в базе или подготовить тестовые данные. Хеш можно сгенерировать в браузере: генератор паролей и bcrypt-хешей считает bcrypt локально и отдаёт строку $2y$12$…, совместимую с Hash::check() и password_verify().
Пароль при этом не отправляется на сервер. В базу записывайте только хеш; сам пароль сохраните в менеджере паролей.
Типичные ошибки
- Двойное хеширование.
Hash::make()при каждом сохранении модели превратит уже готовый хеш в новый — вход перестанет работать. - Сравнение строк вручную. Используйте
Hash::check(), а не===. - Слишком низкий cost. cost 4–6 проверяется почти мгновенно и плохо защищает.
- Ограничение длины пароля. bcrypt принимает длинные строки, но некоторые старые обёртки обрезают их до 72 байт. Не ставьте лимит в 8 символов «для безопасности».
- Логирование пароля. Убедитесь, что пароль не попадает в логи запросов и в трекер ошибок.
Что хранить и как проверять
В таблице пользователей достаточно одного поля password. Не храните рядом «контрольную сумму» или «подсказку». Для сброса используйте одноразовые токены с коротким сроком жизни, а не отправку старого пароля.
Если проект допускает смену алгоритма, например на Argon2id, Laravel поддерживает его через HASH_DRIVER=argon2id. Проверка остаётся прежней: Hash::check() сам определит алгоритм по строке.
Коротко
- храните только bcrypt-хеш, никогда — пароль;
- cost 12 — рабочий вариант по умолчанию;
- проверяйте через
Hash::check(); - хеш можно создать локально в браузере и вставить в базу;
- не логируйте пароли и не хешируйте их повторно.