PasswordEncoder
PasswordEncoder не шифрует пароль для последующей расшифровки. Он вычисляет медленный односторонний password hash и проверяет введённое значение.
String stored = encoder.encode(rawPassword);
boolean matches = encoder.matches(candidate, stored);Требования
- соль должна быть уникальной и генерироваться алгоритмом;
- функция должна быть намеренно дорогой;
- параметры стоимости пересматриваются по возможностям инфраструктуры;
- пароль не логируется и не передаётся после проверки дальше необходимого;
- сравнение выполняется через
matches, а не путём повторного сравнения строк.
Spring поддерживает адаптивные алгоритмы, например bcrypt, PBKDF2, scrypt и Argon2. Конкретный выбор зависит от доступной реализации, памяти, CPU и политики организации.
DelegatingPasswordEncoder
Формат с префиксом хранит алгоритм:
{bcrypt}$2a$...Это позволяет читать старые hashes и записывать новые более сильным алгоритмом. При успешном входе можно проверить upgradeEncoding и пересчитать hash.
Типичные ошибки
- SHA-256 без медленной password-функции;
- одна общая ручная соль;
- детерминированное сравнение
encode(raw).equals(stored); - слишком низкая или чрезмерная стоимость без нагрузочного теста;
- хранение raw password в событии или журнале.
Вопросы для повторения
- Можно ли расшифровать password hash? Нет, проверяется совпадение через вычисление.
- Почему два hash одного пароля различаются? Из-за случайной соли.
- Зачем префикс
{id}? Выбрать encoder для проверки и поддержать миграцию алгоритмов. - Почему обычный SHA недостаточен? Он слишком быстрый для перебора.
- Как обновить старые hashes? Перехешировать после успешной аутентификации или через контролируемый сброс.
Связано: Безопасность приложения Spring Security.