Зачем нужен медленный хеш
Когда база данных утекает, злоумышленники подбирают пароли офлайн по сохранённым хешам. Быстрый хеш вроде SHA-256 позволяет одной GPU перебирать около десяти миллиардов вариантов в секунду, что превращает большинство придуманных людьми паролей в открытый текст за считанные часы. Функции хеширования паролей намеренно медленные и в новых разработках требовательные к памяти, чтобы каждая попытка стоила атакующему столько же, сколько вам, а тысячи ядер GPU не помогали, потому что у них слишком мало общей памяти.
| Функция | Год | Настраивается | Рекомендовано (OWASP 2024) | Когда использовать |
|---|---|---|---|---|
| Argon2id | 2015 | память, проходы, потоки | m=19 MiB, t=2, p=1 (или m=64 MiB, t=3) | По умолчанию для новых систем. Победитель Password Hashing Competition. |
| scrypt | 2009 | N, r, p | N=2¹⁷, r=8, p=1 | Требователен к памяти; подходит там, где Argon2 недоступен. |
| bcrypt | 1999 | стоимость (2ⁿ раундов) | стоимость 10 и выше | Есть везде; по-прежнему надёжен. Обрезает до 72 байт. |
| PBKDF2 | 2000 | итерации | 600 000 (SHA-256) | Соответствие FIPS; не требователен к памяти, поэтому слабее всего против GPU. |
Как читать строку хеша
$2b$12$ + 22 символа соли + 31 символ хеша: bcrypt, стоимость 12 (4 096 раундов). $argon2id$v=19$m=19456,t=2,p=1$salt$hash: Argon2id с параметрами в строке, Base64 без padding. Оба формата содержат всё необходимое для проверки, поэтому со временем можно повышать стоимость и перехешировать пароли пользователей при следующем входе. У scrypt и PBKDF2 нет универсального строкового формата; соль и параметры хранятся отдельно, поэтому проверка запрашивает соль отдельно.
Выбор стоимости
Ориентируйтесь примерно на 100–300 мс на хеш на вашем сервере. Эта страница показывает, сколько времени занял каждый хеш в вашем браузере (приличный ноутбук сопоставим с небольшим серверным ядром). Argon2 с рекомендуемыми 19 MiB занимает около секунды в JavaScript; нативные реализации в несколько раз быстрее.
Чего не делать
Не используйте MD5, SHA-1 или SHA-256 сами по себе, даже с солью. Не используйте одну соль на весь сайт. Не хешируйте предварительно через SHA-256, чтобы обойти 72-байтный лимит bcrypt, если не кодируете результат в Base64 (сырые байты могут содержать NUL, на котором bcrypt останавливается). И не вставляйте реальные боевые пароли ни в одну веб-страницу, включая эту; используйте тестовые значения.
Вопросы
Безопасно ли использовать эту страницу с реальным паролем?
Хеширование выполняется в вашем браузере, и ничего не передаётся, но разумное правило — считать любую веб-страницу недоверенной для реальных учётных данных. Используйте её для генерации хешей для тестовых фикстур, для понимания форматов и для проверки с одноразовыми паролями.
Почему bcrypt каждый раз выдаёт разный хеш?
Соль случайна при каждом вызове; она хранится внутри строки хеша. Проверка извлекает её и пересчитывает. Два хеша одного пароля и должны отличаться; оба проходят проверку.
Почему проверка bcrypt не проходит для длинного пароля?
bcrypt использует только первые 72 байта. Если пароль был захеширован библиотекой с предварительным хешированием (некоторые конфигурации Django и Passlib), сырая проверка bcrypt здесь не совпадёт. Проверьте также префикс: хеши $2y$ и $2b$ совместимы; $2x$ помечает ошибочную реализацию.
Что означают m, t и p в Argon2?
m — память в KiB (19456 = 19 MiB), t — число проходов по этой памяти, p — число потоков (lanes), которые могут работать параллельно. Память — главный регулятор безопасности: именно она делает атаки на GPU и ASIC дорогими.