Прямой ответ на главный вопрос: в 2026 году для хранения паролей в базе данных берите Argon2id с memory cost 64 MiB, iterations 3 и parallelism 2. Если Argon2id недоступен, используйте scrypt с N=2^17, r=8, p=1. bcrypt с cost factor от 12 остается рабочим вариантом для legacy-систем, PBKDF2 с 600 000 итераций HMAC-SHA256 уместен только там, где требуется соответствие FIPS. MD5, SHA-1 и одиночный SHA-256 для паролей не подходят.
Второй по значимости параметр после выбора алгоритма - время одного хеширования. Целевой диапазон 250-500 мс на продакшн-железе: быстрее означает дешевый перебор для атакующего, медленнее грозит падением аутентификации на пике входов.
Ниже разобрано, чем опасны быстрые хеши, как сравнивать bcrypt, scrypt, Argon2id и PBKDF2, как подобрать параметры под реальную нагрузку и что проверить в текущей схеме хранения паролей.
Почему открытое хранение паролей и быстрые хеши - это риск
Пароли нельзя хранить в открытом виде и в виде обратимого шифрования. Обратимое шифрование держит оборону ровно до момента, когда атакующий получает ключ: дамп базы и ключ вместе дают все пароли за один проход. Без ключа дамп все равно остается материалом для офлайн-перебора, и его стойкость определяется только алгоритмом хеширования.
Безопасная схема держится на трех элементах: медленный алгоритм, уникальная соль для каждого пароля и настраиваемая стоимость вычисления, которую можно поднять при росте производительности железа. Быстрые хеш-функции не дают ни одного из этих свойств.
Чем опасны MD5 и SHA-1 для паролей
Скорость. Одна видеокарта класса NVIDIA RTX 4090 считает десятки миллиардов MD5-хешей в секунду, для SHA-1 порядок тот же, но в несколько раз ниже. Пространство перебора для 8-символьного пароля из строчных латинских букв и цифр содержит 36^8, около 2,8 трлн комбинаций. При скорости 10^10-10^11 хешей в секунду полный перебор укладывается в минуты, а среднее время поиска вдвое меньше.
Соль эту проблему не закрывает. Она защищает от заранее просчитанных rainbow tables и мешает вскрыть одинаковые пароли одним вычислением, но перебор конкретного аккаунта идет с той же скоростью.
У MD5, SHA-1 и одиночного SHA-256 нет параметра стоимости. Замедлить их, не меняя алгоритм, невозможно, поэтому с ростом вычислительной мощности стойкость хранилища падает каждый год.
Практический пример: утечка LinkedIn в 2012 году. Пароли хранили как SHA-1 без соли, миллионы учетных записей вскрыли перебором по словарю на обычных GPU. Та же история повторяется с любой базой, где в поле пароля лежит MD5 или SHA-1.
Отдельный случай - встроенные функции СУБД. В MySQL и MariaDB функции PASSWORD() и SHA2() не годятся для паролей пользователей: они либо устарели, либо считают быстрый хеш без растяжения. Разбор функций, прав доступа и переноса хеширования в приложение есть в статье про хранение паролей в MySQL и MariaDB.
Руководство OWASP по хранению паролей ставит Argon2id первым выбором, а NIST SP 800-63B требует соль и растяжение ключа для всех паролей. На эти документы удобно ссылаться, когда выбор алгоритма проходит внутренний аудит или проверку на соответствие PCI DSS.
Что такое соль и почему она обязательна
Соль - случайная строка, уникальная для каждого пароля, длиной от 16 байт, сгенерированная криптографически стойким генератором (CSPRNG). Хранится она рядом с хешем в открытом виде, и это нормально: секретность соли не нужна, важна уникальность.
Два пользователя с одинаковым паролем получат разные хеши, поэтому одна найденная строка словаря не открывает однотипные аккаунты. bcrypt и Argon2 включают соль в выходную строку автоматически, у PBKDF2 соль передается отдельным параметром, и хранить ее приходится самому.
Генерация соли, хранение перца в KMS и Vault, типичные ошибки при работе с ними разобраны в отдельном материале про соль и перец в хешировании паролей.
Обзор алгоритмов хеширования паролей: bcrypt, scrypt, Argon2id, PBKDF2
Все четыре алгоритма решают одну задачу: сделать проверку пароля дорогой для того, у кого оказался дамп базы. Разница в том, чем именно платит атакующий: временем CPU, памятью или тем и другим.
Argon2id: рекомендации OWASP и параметры по умолчанию
Argon2id победил в Password Hashing Competition в 2015 году и описан в RFC 9106. Гибридный режим соединяет устойчивость Argon2i к атакам по сторонним каналам и сопротивление Argon2d к перебору на GPU. Настройка идет тремя параметрами: memory cost (в MiB), iterations (time cost) и parallelism (число потоков).
OWASP приводит минимальный порог: memory cost 19 MiB (19456 KiB), iterations 2, parallelism 1. Для чувствительных сервисов рекомендуются memory cost 64 MiB, iterations 3, parallelism 4. Значения не догма: подбирайте их так, чтобы одно хеширование занимало 250-500 мс на продакшн-сервере.
Библиотеки: libsodium (crypto_pwhash), argon2-cffi и passlib для Python, PASSWORD_ARGON2ID в PHP, пакет argon2 в Node.js, x/crypto/argon2 в Go. Строки хешей переносимы между языками, поэтому миграция между стеками не требует пересчета паролей.
bcrypt: ограничения и актуальность в 2026 году
bcrypt появился в 1999 году на основе шифра Blowfish и остается самым распространенным вариантом. Параметр cost factor (work factor) задает число раундов как 2^cost, время вычисления растет экспоненциально. Для 2026 года рабочий диапазон 12-14: cost 12 дает около 250 мс на современном серверном CPU, cost 14 примерно в четыре раза дольше.
Ограничение известно: bcrypt обрезает пароль до 72 байт. Для длинных passphrase хвост строки не влияет на хеш. Обходной путь - сначала посчитать HMAC-SHA256 от пароля и закодировать результат в base64, затем подать его на вход bcrypt.
Второе ограничение: bcrypt не memory-hard. Основная стоимость - время CPU, память почти не расходуется, поэтому FPGA и ASIC получают преимущество перед обычными GPU. Для legacy-систем это приемлемо, для новых проектов Argon2id предпочтительнее. Поддержка: bcrypt в Node.js, passlib в Python, password_hash с PASSWORD_BCRYPT в PHP.
scrypt: memory-hard подход и его особенности
scrypt предложил Колин Персивал в 2009 году, спецификация закреплена в RFC 7914. Алгоритм memory-hard: параметр N задает число блоков, r - размер блока, p - степень параллелизма. Расход памяти считается как 128 × N × r байт, поэтому подъем N прямо увеличивает требования к RAM и делает перебор на GPU и ASIC невыгодным.
Практичные значения: N=2^17 (131072), r=8, p=1. Это около 128 MiB памяти на одно вычисление и задержка в сотни миллисекунд.
scrypt есть в OpenSSL (EVP_PBE_scrypt) и libsodium (crypto_pwhash_scryptsalsa208sha256), что позволяет обойтись без сторонних библиотек. Осторожность нужна при выборе N: слишком большое значение исчерпает память сервера на пиковой нагрузке. ASIC для майнинга Litecoin рассчитаны на низкомные параметры (N=1024, r=1, p=1) и к рекомендованным настройкам неприменимы.
PBKDF2: когда он всё ещё уместен
PBKDF2 стандартизирован в RFC 8018 и входит в требования FIPS 140-2/140-3, из-за чего часто остается единственным допустимым вариантом в регулируемых средах. Работает он на HMAC (чаще HMAC-SHA256), главный параметр - число итераций.
OWASP для 2026 года называет минимум 600 000 итераций для PBKDF2-HMAC-SHA256. На современном серверном CPU это 0,3-0,5 с, что попадает в целевой диапазон задержки. Слабое место - низкое потребление памяти: GPU-ферма считает итерации параллельно, и разрыв между CPU и GPU здесь выше, чем у memory-hard алгоритмов.
Вывод по применимости: PBKDF2 держите там, где есть требование FIPS или где другие реализации недоступны. Для новых проектов без таких ограничений выбор сводится к Argon2id, scrypt и bcrypt.
Сравнение по ключевым критериям:
| Алгоритм | Год | Параметры стоимости | Память на одно хеширование | Стойкость к GPU/ASIC | Стандарт и статус |
|---|---|---|---|---|---|
| Argon2id | 2015 | memory cost, iterations, parallelism | 19-64 MiB и выше, задается вручную | Высокая | RFC 9106, первый выбор OWASP |
| scrypt | 2009 | N, r, p | около 128 MiB при N=2^17, r=8 | Высокая | RFC 7914 |
| bcrypt | 1999 | cost factor 4-31 | менее 1 MiB | Средняя | де-факто стандарт, RFC нет |
| PBKDF2 | 2000 | iterations, salt | менее 1 MiB | Низкая | RFC 8018, требования FIPS |
| MD5, SHA-1 | 1992, 1995 | отсутствуют | менее 1 MiB | Не защищает | Не применять для паролей |
Как подобрать параметры хеширования под реальную нагрузку
Ориентир один: одно хеширование на продакшн-железе должно занимать 250-500 мс. Меньше - атакующему дешевле перебирать, больше - растет риск, что пик входов положит аутентификацию.
Методика бенчмарка: измеряем время хеширования
Порядок действий:
- Возьмите инстанс того же класса, что и продакшн: те же CPU, объем RAM, тип диска и та же виртуализация.
- Запустите 100 хеширований с целевыми параметрами и запишите время каждого прогона.
- Смотрите на среднее и на 95-й перцентиль: первое показывает типичную задержку, второй - поведение под нагрузкой.
- Повторите замер при конкурентной нагрузке, например при работающих соседних сервисах.
Пример замера для Argon2id на Python:
import time
import argon2
ph = argon2.PasswordHasher(time_cost=3, memory_cost=65536, parallelism=2)
samples = []
for _ in range(100):
start = time.perf_counter()
ph.hash("benchmark-password")
samples.append(time.perf_counter() - start)
samples.sort()
avg = sum(samples) / len(samples) * 1000
p95 = samples[94] * 1000
print("avg: %.0f ms, p95: %.0f ms" % (avg, p95))
Для сравнения вариантов удобен hyperfine: он сам прогревает команду и считает статистику по нескольким запускам. Виртуализация добавляет разброс, поэтому замер на ноутбуке ничего не говорит о сервере. Если продакшн живет в облаке, поднимите тестовый инстанс с тем же классом CPU, например в Timeweb Cloud, и перенесите замеры туда: разница между shared и выделенными ядрами легко меняет время хеширования в разы.
Влияние параметров на память и CPU
Argon2id: memory cost задает расход RAM на одно хеширование напрямую, iterations добавляют время CPU, parallelism определяет число потоков и одновременно умножает потребление памяти. При m=64 MiB и p=2 одно вычисление забирает около 128 MiB.
scrypt: N и r влияют и на память, и на CPU, p добавляет параллелизм. bcrypt расходует только CPU, память почти не задействована. У PBKDF2 стоимость тоже целиком в CPU.
Считайте пиковую нагрузку. Сто одновременных входов с Argon2id при m=64 MiB дают 6,4 ГиБ памяти в моменте, у bcrypt cost 12 та же сотня входов укладывается в десятки мегабайт, но загружает все ядра. Отсюда два вывода: для memory-hard алгоритмов нужен запас RAM и очередь на аутентификацию, для CPU-зависимых - лимит на число одновременных проверок.
Rate limiting, блокировка аккаунтов после серии неудач и защита от timing-атак снижают нагрузку на хеширование и закрывают онлайн-перебор. Готовые конфигурации для Nginx и fail2ban, а также значения cost factor для bcrypt и Argon2id собраны в руководстве по защите хранилища паролей от брутфорса.
В Kubernetes ограничивайте ресурсы pod-ов, которые занимаются аутентификацией. CPU-лимит ниже реальной потребности приводит к троттлингу и скачкам задержки, а memory-лимит ниже memory cost Argon2id заканчивается OOMKilled на первом же пике. Параметры пересматривайте раз в 1-2 года и после каждой смены железа.
Практическая реализация: хранение, миграция и обновление хешей
Строка хеша несет в себе все, что нужно для проверки: алгоритм, параметры, соль и результат. Это упрощает и хранение, и последующую миграцию параметров.
Формат хранения хеша и соли
Argon2id с memory cost 64 MiB, iterations 3, parallelism 2:
$argon2id$v=19$m=65536,t=3,p=2$c29tZXNhbHR2YWx1ZQ$aGFzaGVkLXBhc3N3b3JkLXZhbHVl
bcrypt с cost 12:
$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/HS.iK2a
Поле в базе: VARCHAR(255) хватает и для Argon2id с крупными параметрами, и для bcrypt. Если схема использует BYTEA, длина та же, отличается только кодировка. Типы полей, индексы и защита от утечек через логи и бэкапы описаны в материале про схему таблицы пользователей для безопасного хранения паролей.
Pepper хранится отдельно от базы: в KMS, Vault или переменных окружения приложения. Перед хешированием к паролю применяют HMAC-SHA256 с ключом-перцем. Это дает выигрыш при утечке только дампа: без ключа перебор невозможен, а при использовании bcrypt попутно решается проблема 72 байт, потому что на вход подается base64-строка фиксированной длины.
Миграция на новый алгоритм без сброса паролей
Сброс паролей всей базы - самый дорогой путь: поток обращений в поддержку, рост числа сбросов через почту, риск блокировки аккаунтов. Рабочая альтернатива - ленивое перехеширование при входе.
Схема: в таблице пользователей остается одно поле хеша, алгоритм и параметры определяются по префиксу строки. При успешной проверке пароля приложение смотрит, соответствуют ли параметры текущим, и если нет, считает новый хеш и перезаписывает поле. Пользователи, которые не входят, остаются на старом хеше, но он продолжает проверяться.
Пример на Python с passlib:
from passlib.context import CryptContext
ctx = CryptContext(
schemes=["argon2", "bcrypt"],
deprecated=["bcrypt"],
argon2__time_cost=3,
argon2__memory_cost=65536,
argon2__parallelism=2,
)
ok, new_hash = ctx.verify_and_update(plain_password, stored_hash)
if ok and new_hash:
update_password_hash(user_id, new_hash)
Комментарий к коду: verify_and_update возвращает флаг успешной проверки и новую строку хеша, если текущая схема устарела. Отдельное поле hash_version или password_algo нужно тогда, когда префикса недостаточно, например при хранении SHA-1 без соли. Порядок шагов, метрики и план отката разобраны в статье про миграцию паролей на Argon2id и bcrypt без сброса.
Контрольные точки при миграции: доля аккаунтов на новом алгоритме растет по метрике в дашборде, ошибки проверки не превышают базовый уровень, откат не требует обратного перехеширования и сводится к возврату старых параметров проверки. Для пользователей, которые не входили больше 6-12 месяцев, разумно инициировать сброс пароля при следующей попытке входа. Черновые скрипты миграции и разбор ошибок удобно прогонять через LLM: агрегатор AiTunnel дает единый доступ к 200+ моделям GPT, Gemini и Claude с оплатой в рублях и без VPN, что экономит время на ревью кода аутентификации.
Чек-лист для аудита текущей схемы хранения паролей
Двенадцать проверок, которые проходятся за один вечер по текущей базе и коду аутентификации.
- Пароли не хранятся в открытом виде и не шифруются обратимым ключом. Проверяется по коду записи и чтения поля.
- Используется медленный алгоритм: Argon2id, scrypt, bcrypt или PBKDF2.
- MD5, SHA-1 и одиночный SHA-256 без растяжения не применяются ни в одном месте схемы.
- Соль уникальна для каждого пароля, длина от 16 байт, генерация через CSPRNG.
- Параметры соответствуют рекомендациям OWASP на 2026 год: Argon2id m не ниже 19 MiB, t не ниже 2, p не ниже 1; bcrypt cost от 12; PBKDF2-HMAC-SHA256 от 600 000 итераций; scrypt N=2^17, r=8.
- Время одного хеширования на продакшн-железе укладывается в 250-500 мс.
- Параметры можно поднять без сброса паролей: есть поле версии хеша или определение алгоритма по префиксу.
- Pepper, если используется, хранится вне базы: KMS, Vault, переменные окружения, и не попадает в резервные копии.
- Доступ к таблице пользователей ограничен отдельной ролью, у приложения нет лишних прав на чтение.
- Пароли и хеши не попадают в логи, трассировки, дампы и сообщения об ошибках.
- Бенчмарк проведен на целевом инстансе с учетом пиковой нагрузки и числа одновременных входов.
- Аудит повторяется раз в 6-12 месяцев, после смены железа и после каждого инцидента.
Один невыполненный пункт обычно и определяет реальный уровень защиты: если хеш слабый, ограничение доступа к базе не спасет после утечки дампа, а если параметры не пересматривались три года, стойкость упала вместе со стоимостью железа.
Итог: что выбрать в 2026 году
Для нового проекта: Argon2id с memory cost 64 MiB, iterations 3, parallelism 2 и выше, если позволяет железо. Минимальный порог OWASP (m=19 MiB, t=2, p=1) подходит для сервисов с жесткими ограничениями по RAM, но запас лучше держать выше минимума.
Если Argon2id недоступен: scrypt с N=2^17, r=8, p=1. bcrypt с cost factor от 12 остается допустимым для legacy и для сред, где менять библиотеки дорого. PBKDF2 с 600 000 итераций HMAC-SHA256 применяйте только под требование FIPS. MD5 и SHA-1 не используйте ни в каком виде, включая встроенные функции СУБД.
Дальше три действия: замерить хеширование на продакшн-железе и выставить параметры под 250-500 мс, настроить перехеширование при входе, пройти по чек-листу из 12 пунктов. Параметры стоит пересматривать раз в 1-2 года: железо дешевеет, стоимость перебора падает, а хеши в базе остаются теми же.