Skip to content
Назад к блогу
Безопасность

bcrypt vs Argon2 vs scrypt: хеширование паролей в 2026 году

Сравнение bcrypt, Argon2id и scrypt по параметрам OWASP 2026 — гайд по выбору алгоритма с примерами кода.

18 мин чтения

bcrypt vs Argon2 vs scrypt: хеширование паролей в 2026 году

Хеширование ≠ шифрование. Хеш — необратимый отпечаток фиксированной длины: ни сервер, ни атакующий не способны восстановить исходный пароль. Шифрование, напротив, обратимо при наличии ключа. Для паролей всегда применяется хеширование, никогда не шифрование — это базовое требование, на котором стоит вся остальная аргументация ниже. Если на собеседовании или в архитектурном ревью вы видите фразу «зашифрованные пароли в БД» — это инженерный red flag, не лингвистическая придирка.

Короткий ответ: для любого нового проекта в 2026 году используйте Argon2id с m=19456, t=2, p=1. Это совпадает с базовой рекомендацией OWASP Password Storage Cheat Sheet и даёт лучшую устойчивость к GPU и побочным каналам, какую можно отгрузить сегодня.

Если Argon2 нет в вашем стеке (редко, но бывает на встроенных или старых рантаймах), берите scrypt с N=2^17, r=8, p=1. bcrypt с cost=12 — только тогда, когда вы заперты в legacy-системе, которая уже умеет bcrypt, и добавить новую зависимость нельзя. PBKDF2-HMAC-SHA-256 с 600 000 итераций — когда обязательно соответствие FIPS-140.

АлгоритмПараметры OWASP 2026Когда выбирать
Argon2idm=19456 KiB, t=2, p=1По умолчанию для новых проектов
scryptN=2^17, r=8, p=1Когда Argon2 недоступен
bcryptcost=12 (мин 10)Только legacy-системы
PBKDF2HMAC-SHA-256, 600k итерацийТребуется FIPS-140

Дальше в статье — почему именно эти числа, как настроить их под ваше железо и как мигрировать без принудительного сброса паролей. Если нужны крепкие тестовые пароли для бенчмарков, возьмите генератор случайных паролей. Для общей картины — руководство по основам веб-безопасности.

Чем хеширование паролей отличается от обычного хеширования

Снаружи хеш-функции выглядят одинаково: на входе — данные, на выходе — отпечаток фиксированной длины, обратить нельзя. Но цели проектирования у «вычислить хеш ISO-образа на 4 ГБ» и «вычислить хеш 12-символьного пароля» тянут в противоположные стороны. Один должен работать так быстро, как позволяет кремний. Другой — так медленно, как позволяет бюджет задержки на логин.

Перепутывание этих двух задач — и есть тот канал, по которому утечка базы превращается в захват аккаунтов.

Почему MD5 и SHA-256 не подходят для паролей

Универсальные хеши вроде MD5, SHA-1 и SHA-256 строились ради пропускной способности. Они дают гигабайты в секунду на обычном CPU и десятки гигабайтов в секунду на GPU. Это отлично для контрольных сумм файлов и контент-адресации, и катастрофично для паролей.

Бенчмарки Hashcat на одной RTX 4090 в 2024-м показывают примерно 164 ГГц/с для MD5 и 22 ГГц/с для SHA-256. Восьмисимвольный пароль «нижний регистр + цифры» (36^8 ≈ 2,8 × 10^12 кандидатов) ложится одной GPU меньше чем за минуту против MD5 и за пару минут против SHA-256. База с sha256(password) — фактически plaintext.

Соль не спасёт. Она блокирует предвычисленные радужные таблицы, но никак не замедляет атаку по одному аккаунту: атакующий просто вычисляет хеш каждого кандидата с утёкшей солью.

Для не-security контрольных сумм MD5 и SHA-256 свою работу делают; для этого и есть инструменты вроде общего генератора хешей. Развёрнутое сравнение «когда какой алгоритм уместен» — в сравнении MD5 и SHA-256. Но для паролей нужен хеш, который специально работает медленно.

Что обязан делать современный хеш пароля

Хеш пароля, достойный отгрузки в 2026-м, имеет три свойства:

  1. Намеренно медленный, с настраиваемым work factor. Логин должен занимать 100–500 мс: достаточно быстро, чтобы пользователь не замечал, достаточно медленно, чтобы offline-атакующий тратил дни на миллион попыток. Work factor должен быть параметром, чтобы его можно было поднимать по мере улучшения железа.
  2. Соль на запись. Уникальная случайная соль на каждый пароль ломает радужные таблицы и заставляет атакующего бить по каждому аккаунту отдельно. Современные алгоритмы сами генерируют и встраивают соль в выходную строку.
  3. Memory-hard. GPU и ASIC быстры в вычислениях, но дороги в высокопропускной памяти. Алгоритм, требующий десятки МБ на хеш, заставляет атакующего обеспечивать RAM пропорционально параллелизму, что убивает экономику GPU-ферм.

bcrypt вытягивает (1) и (2), но не (3). scrypt — первый алгоритм, попавший во все три. Argon2 уточнил дизайн и выиграл Password Hashing Competition. Дальше разбираем каждый.

Три алгоритма: архитектура и компромиссы

bcrypt: на основе Blowfish, time-hard

bcrypt спроектирован в 1999-м Нильсом Провосом и Дэвидом Мазьером для OpenBSD. Построен на шифре Blowfish с дорогостоящей фазой инициализации ключа («EksBlowfish»), повторяемой 2^cost раз. Единственный настраиваемый параметр — cost factor (он же «log rounds»): каждое приращение удваивает работу. cost=10 делает 1024 раундов установки ключа; cost=14 — 16 384.

Хеш bcrypt выглядит так:

$2b$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
 │  │  │                      │
 │  │  │                      └─ 31-символьный base64 хеш
 │  │  └─ 22-символьная base64 соль
 │  └─ cost factor (12)
 └─ идентификатор алгоритма ($2b$ = bcrypt v2)

Формат самоописывающий: verify() читает cost и соль из сохранённой строки, отдельные колонки не нужны.

Минусы реальны. Footprint памяти у bcrypt — около 4 КБ, достаточно мало, чтобы топовая GPU гоняла тысячи bcrypt-ядер параллельно. И bcrypt тихо обрезает вход на 72 байтах. У 100-символьной парольной фразы та же безопасность, что и у её первых 72 байт. Максимальный cost — 31, но всё, что выше ~16, начинает бить по задержке логина на обычном железе.

scrypt: пионер memory-hard

scrypt опубликовал в 2009-м Колин Персиваль для сервиса бэкапов Tarsnap, стандартизирован как RFC 7914 в 2016-м. Он ввёл идею memory-hardness: алгоритм заполняет большой буфер псевдослучайными данными, затем читает из случайных позиций, заставляя любую реализацию реально выделить эту память.

scrypt берёт три параметра:

  • N — стоимость по CPU/памяти (должна быть степенью двойки)
  • r — размер блока в байтах (множитель на память и раунды смешивания)
  • p — параллелизм (независимые вычисления, в основном для масштабирования CPU-времени без масштабирования памяти)

Использование памяти примерно 128 × N × r байт. С рекомендованными OWASP N=2^17, r=8 это 128 × 131072 × 8 = 134 217 728 байт, или 128 МБ на хеш.

scrypt также работает как функция деривации ключа, а не только как хеш пароля. Его можно встретить в кошельках криптовалют, полнодисковом шифровании и оригинальном proof-of-work Litecoin. Эта двойная роль удобна, когда нужны и хранение пароля, и деривация ключа в одной библиотеке.

Argon2 (id/i/d): победитель Password Hashing Competition

Password Hashing Competition шёл с 2013 по 2015 год, оценивая 24 кандидата по memory-hardness, устойчивости к побочным каналам и простоте реализации. Победил Argon2. Стандартизирован как RFC 9106 в 2021-м.

У Argon2 три варианта. Различие — в том, как адресуется память при смешивании:

  • Argon2d использует data-dependent адреса памяти. Это даёт лучшую устойчивость к атакам GPU и ASIC, но утекает информацию через побочные каналы кеш-таймингов. Подходит для proof-of-work криптовалют, не для аутентификации.
  • Argon2i использует data-independent адреса. Безопасен по побочным каналам, но чуть слабее против GPU-tradeoff атак.
  • Argon2id — гибрид: первая половина первого прохода использует индексирование Argon2i (безопасно по побочным каналам), остальное — индексирование Argon2d (устойчивость к GPU). RFC 9106 явно рекомендует Argon2id для хеширования паролей, и так же делает OWASP.

Argon2 берёт три параметра:

  • m — память в КБ
  • t — стоимость по времени (число проходов по буферу памяти)
  • p — параллелизм (число дорожек, обрабатываемых одновременно)

Хеш Argon2id использует формат строки PHC и выглядит так:

$argon2id$v=19$m=19456,t=2,p=1$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG

Как и в bcrypt, все параметры живут внутри строки, поэтому verify() не нужна таблица параметров.

Рекомендуемые параметры OWASP 2026

OWASP Password Storage Cheat Sheet — канонический ориентир. Числа ниже соответствуют его текущему гайдансу. Они консервативные, рассчитаны на типовой веб-сервер с бюджетом задержки 100–500 мс на логин, и вы всё равно должны провести бенчмарк на собственном железе перед отгрузкой.

Параметры Argon2id: первый выбор

Базовая рекомендация OWASP: m=19456 (19 МБ), t=2, p=1.

Если у вашего сервера больше запаса по RAM, работу можно перераспределить между памятью и временем. RFC 9106 публикует эквивалентные профили; OWASP допускает любой из этих:

memoryCost (m)timeCost (t)parallelism (p)RAM на хеш
471041146 МБ
194562119 МБ (базовый)
122883112 МБ
9216419 МБ
7168517 МБ

Эвристика настройки. Сначала выберите m исходя из пикового бюджета RAM на одновременные логины. Если ожидается 100 одновременных логинов и есть 4 ГБ запаса — это 40 МБ на хеш. Затем увеличивайте t, пока один verify не займёт 100–500 мс на вашем продакшен-CPU. Оставьте p=1, если нет конкретной причины задействовать многоядерность (большинство веб-фреймворков и так дают каждому запросу свой поток).

Параметры scrypt: когда Argon2 недоступен

Рекомендация OWASP: N=2^17 (131072), r=8, p=1, что использует 128 МБ на хеш.

Если 128 МБ на одновременный логин — слишком много для вашего сервера, OWASP допускает более слабые профили:

NrpRAM на хеш
2^1781128 МБ (предпочтительно)
2^168164 МБ
2^158132 МБ

N должен быть степенью двойки. Увеличение r поднимает и память, и работу CPU пропорционально; увеличение p поднимает работу CPU без роста памяти на инстанс. Для хеширования паролей оставляйте r и p на дефолтах и крутите только N.

bcrypt: cost factor 10+ только для legacy

OWASP больше не рекомендует bcrypt для новых проектов, но он по-прежнему повсюду: Devise, Spring Security, ASP.NET Identity и бесчисленные самодельные системы аутентификации по умолчанию используют его.

Если вы заперты в bcrypt — правила такие:

  • Минимальный cost factor: 10. Ниже 10 — одна GPU дочитает утёкшую базу за дни.
  • Рекомендуется: 12–14, в зависимости от железа. На современном x86-сервере cost=12 берёт ~250 мс на хеш; cost=13 — 500 мс.
  • Целевой диапазон 100–300 мс на verify на вашем продакшен-железе. Бенчмарк, не угадывание.
  • Помните о лимите 72 байта на вход. Если пользователи могут выбирать парольные фразы, предварительно вычислите SHA-256 (см. FAQ).

Устойчивость bcrypt к GPU ограничена его 4-килобайтным footprint памяти. Никакой cost factor никогда не сравняется с memory-hardness Argon2id, поэтому выбирайте Argon2id, когда можете.

Для практического ориентира: на сервере EPYC 2024 года bcrypt(cost=12) выполняется примерно за 250 мс; на топовом ноутбуке — ближе к 350 мс. Если ваши числа отличаются от 100–500 мс на порядок, проверьте, действительно ли библиотека использует нативный bcrypt, а не падает в медленный JS-полифил (некоторые сборщики выбрасывают нативные зависимости в serverless-сборках).

PBKDF2: путь соответствия FIPS-140

PBKDF2 (RFC 8018) — алгоритм последней инстанции в гайдансе по безопасности. Он старше bcrypt, не memory-hard и сдаёт GPU-атакам быстрее любого из трёх выше. Но он — единственный примитив хеширования паролей, валидированный по FIPS-140, что важно для федерального правительства, медицины (HIPAA) и определённых финансовых деплоев.

Когда нужен PBKDF2, используйте:

  • HMAC-SHA-256 как PRF (не SHA-1; не голый SHA-256 без HMAC)
  • Минимум 600 000 итераций (базовый OWASP 2026)
  • Минимум 16-байтная случайная соль на пароль

Если FIPS вас не касается — берите Argon2id. Фиксированный вывод и фиксированная память PBKDF2 значат, что каждый доллар, вложенный атакующим в кремний GPU, напрямую конвертируется в больше попыток в секунду.

NIST SP 800-63B называет PBKDF2-HMAC «approved» для хеширования паролей, но не доходит до того, чтобы рекомендовать его поверх memory-hard альтернатив. Читайте это так: NIST позволяет PBKDF2 потому, что иначе пришлось бы инвалидировать каждый legacy-деплой государства, а не потому, что это лучший выбор для greenfield-проекта.

Рамка решения: какой алгоритм выбрать?

Сравнительная таблица

ПараметрbcryptscryptArgon2idPBKDF2
Memory-hardНетДаДаНет
Устойчивость к GPUСредняяВысокаяОчень высокаяНизкая
Устойчивость к побочным каналамСредняяСредняяВысокая (id)Средняя
Сложность параметров1 (cost)3 (N, r, p)3 (m, t, p)1 (iterations)
Зрелость библиотекОтличнаяХорошаяХорошаяОтличная
Лимит длины входа72 байтаНетНетНет
Стандартизацияde factoRFC 7914RFC 9106RFC 8018
Статус OWASP 2026Только legacyАльтернативаПервый выборТолько FIPS

По умолчанию — Argon2id

Для нового проекта (типовое веб-приложение, современный стек Node/Python/Go/Rust/JVM, без FIPS-ограничений) — используйте Argon2id с m=19456, t=2, p=1. Получаете лучшую устойчивость к GPU и побочным каналам, доступную сегодня, формат с встроенными параметрами, переживающий апгрейды библиотек, и никакого 72-байтного лимита. Экосистема библиотек зрелая: argon2 в npm, argon2-cffi в PyPI, golang.org/x/crypto/argon2, крейт argon2 на crates.io — всё поддерживается и проходит бенчмарки.

Когда выбрать scrypt или bcrypt

Берите scrypt, когда Argon2 недоступен в вашем рантайме (по-настоящему редко в 2026-м; даже Cloudflare Workers и Deno его теперь поддерживают), или когда у вас уже есть scrypt-система в продакшене и стоимость миграции перевешивает прирост безопасности. scrypt — по-прежнему добротный алгоритм; ему просто не хватает шлифовки Argon2id по побочным каналам.

Берите bcrypt, когда вы поддерживаете legacy-систему, у вас жёсткое требование минимизации зависимостей (никакого нативного кода, никаких лишних пакетов) и 72-байтный лимит приемлем для вашей пользовательской базы. bcrypt отработал на интернет-масштабе два десятилетия; его сценарии отказа задокументированы.

Берите PBKDF2, когда так сказал регулятор. Это единственная причина. Если ваш аудитор примет Argon2id (а всё больше принимают для не-FIPS нагрузок) — берите Argon2id.

Распространённые ошибки

Большинство утечек хранения паролей за последнее десятилетие сводятся к горстке повторяющихся инженерных ошибок. Ни одна не экзотическая, и все ловятся ревью кода аутентификации со списком ниже перед глазами.

  • Хеширование паролей голым SHA-256 или MD5. Самый крупный провал в хранении паролей. См. сравнение MD5 и SHA-256 о том, почему это неверно для паролей.
  • Использование одной глобальной соли на всех пользователей. Соль обязана быть уникальной на запись. Argon2 и bcrypt сами генерируют её для вас; не переопределяйте это.
  • Установка времени хеша ниже 50 мс. Вы обменяли безопасность на ускорение, которое пользователь не способен заметить. Цельтесь в 100–500 мс.
  • Установка времени хеша выше 1 секунды. Вы создали DoS-вектор против собственного endpoint логина. Ограничьте сверху ~500 мс.
  • Хеширование паролей на клиенте и отправка дайджеста на сервер. Хеш стал паролем. Любой, кто украл базу, может аутентифицироваться, не обращая хеш. Хешируйте на сервере, точка.
  • Хранение параметров алгоритма в отдельной колонке. Формат строки PHC сам кладёт их в хеш. Используйте его.
  • Логирование паролей или хешей в обработке ошибок. И то и другое — собственность пользователя, не вашего лог-агрегатора. Скрабьте их на слое разбора запроса до того, как они дойдут до любого логгера.
  • Трактовка исключений verify() как ошибок аутентификации. Библиотека, бросающая исключение на повреждённом сохранённом хеше, должна вынести ошибку наверх, а не молча провалиться в «неверный пароль». Различайте «неверный пароль» (вернуть 401) и «сохранённый хеш повреждён» (вернуть 500 и поднять on-call).

Реальная имплементация

Argon2id в Node.js

Пакет argon2 (нативные биндинги к референсной реализации) — канонический выбор в Node:

import argon2 from 'argon2';

// Хеширование при регистрации или смене пароля
const hash = await argon2.hash(password, {
  type: argon2.argon2id,
  memoryCost: 19456,  // 19 МБ
  timeCost: 2,
  parallelism: 1,
});
// → '$argon2id$v=19$m=19456,t=2,p=1$<salt>$<hash>'

// Verify при логине
const ok = await argon2.verify(hash, candidate);
if (!ok) throw new Error('Invalid credentials');

// Обнаружение устаревших параметров и re-hash при успешном логине
if (argon2.needsRehash(hash, { type: argon2.argon2id, memoryCost: 19456, timeCost: 2, parallelism: 1 })) {
  const upgraded = await argon2.hash(candidate, {
    type: argon2.argon2id, memoryCost: 19456, timeCost: 2, parallelism: 1,
  });
  await db.users.update({ id: user.id }, { password_hash: upgraded });
}

Шаг needsRehash — то, что делает долгосрочную миграцию безболезненной: каждый успешный логин становится возможностью обновить сохранённый хеш до текущих параметров, не беспокоя пользователя.

Тот же паттерн в Python с argon2-cffi:

from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError

ph = PasswordHasher(memory_cost=19456, time_cost=2, parallelism=1)

# Hash
stored = ph.hash(password)

# Verify
try:
    ph.verify(stored, candidate)
except VerifyMismatchError:
    raise ValueError('Invalid credentials')

# Re-hash при апгрейде параметров
if ph.check_needs_rehash(stored):
    stored = ph.hash(candidate)

В Go с golang.org/x/crypto/argon2:

import (
    "crypto/rand"
    "golang.org/x/crypto/argon2"
)

func hashPassword(password string) ([]byte, []byte) {
    salt := make([]byte, 16)
    rand.Read(salt)
    hash := argon2.IDKey([]byte(password), salt, 2, 19456, 1, 32)
    return hash, salt
}

Стандартная библиотека Go не поставляет PHC-форматирование; если используете примитив argon2.IDKey напрямую, придётся самому кодировать параметры и соль рядом с хешом. Большинство Go-проектов используют обёртку вроде github.com/alexedwards/argon2id.

Rust с крейтом argon2 идиоматически похож:

use argon2::{Argon2, PasswordHasher, PasswordVerifier, password_hash::{SaltString, rand_core::OsRng}};

let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();  // Argon2id, m=19456, t=2, p=1 по умолчанию
let hash = argon2.hash_password(password.as_bytes(), &salt)?.to_string();

// На verify
let parsed = argon2::password_hash::PasswordHash::new(&hash)?;
argon2.verify_password(candidate.as_bytes(), &parsed)?;

Во всех трёх рантаймах получаемая строка взаимозаменяема: хеш, созданный в Node, корректно проверяется в Python или Rust. Эта кросс-рантаймовая совместимость делает Argon2 более безопасной ставкой для полиглотных архитектур, чем алгоритм-специфичные обёртки.

Паттерн миграции bcrypt → Argon2id

Почти никогда не получится снести таблицу пользователей и начать заново. Реально работает паттерн «мягкого, ведомого логином» апгрейда:

Добавляем колонку для отслеживания алгоритма:

ALTER TABLE users ADD COLUMN password_algo VARCHAR(16) NOT NULL DEFAULT 'bcrypt';

При логине отправляем в нужный verifier:

async function verifyAndMaybeRehash(user, candidate) {
  let ok;
  if (user.password_algo === 'argon2id') {
    ok = await argon2.verify(user.password_hash, candidate);
  } else if (user.password_algo === 'bcrypt') {
    ok = await bcrypt.compare(candidate, user.password_hash);
    if (ok) {
      // Успешный legacy verify → re-hash через Argon2id
      const newHash = await argon2.hash(candidate, {
        type: argon2.argon2id, memoryCost: 19456, timeCost: 2, parallelism: 1,
      });
      await db.users.update({ id: user.id }, {
        password_hash: newHash,
        password_algo: 'argon2id',
      });
    }
  }
  return ok;
}

Установите окно sunset в 6–12 месяцев. На 9-м месяце пошлите письмо «ваш пароль хранится по устаревшему методу, пожалуйста, войдите для апгрейда». После 12-ти месяцев аккаунты, оставшиеся на bcrypt, требуют принудительного сброса пароля при следующем логине. Активные пользователи мигрируют прозрачно; неактивные получают одноразовое трение.

Тот же паттерн работает для миграции с scrypt или PBKDF2. Вся нужная вам state — колонка password_algo.

Pepper, лимиты длины и подводные камни кодировки

Несколько острых углов, которые кусают реальные деплои:

Pepper. Pepper — секрет уровня приложения, добавляемый к каждому паролю перед хешированием, хранящийся отдельно от базы (в KMS, env-переменной или Hashicorp Vault). Если ваша база утекла, а app-секрет — нет, утёкшие хеши неатакуемы без pepper. Применяйте через HMAC, не конкатенацией:

import { createHmac } from 'crypto';
const peppered = createHmac('sha256', process.env.PEPPER).update(password).digest();
const hash = await argon2.hash(peppered, { type: argon2.argon2id, /* ... */ });

Pepper ротируйте редко (это требует re-hash), но поддерживайте ротацию через версионирование: PEPPER_V2, с фолбэком на PEPPER_V1 при verify.

Лимит 72 байта в bcrypt. Если приходится использовать bcrypt и поддерживать пароли произвольной длины, предварительно вычислите SHA-256 и закодируйте base64 (избегая встроенных NUL-байтов, которые bcrypt также обрабатывает непоследовательно):

import { createHash } from 'crypto';
const prepped = createHash('sha256').update(password, 'utf8').digest('base64');
const hash = await bcrypt.hash(prepped, 12);

То же преобразование prepped обязано выполняться на verify. Задокументируйте это в коде аутентификации огромным комментарием, чтобы следующий, кто туда полезет, понял, что происходит.

Нормализация UTF-8. Строка "café" может быть закодирована как c-a-f-é (4 кодпоинта, NFC) или c-a-f-e + комбинирующий акут (5 кодпоинтов, NFD). Они выглядят одинаково, но дают разные хеши. Всегда нормализуйте к NFC перед хешированием:

const normalized = password.normalize('NFC');

Это кусает мобильные клавиатуры и copy-paste из PDF чаще, чем кажется.

Никогда не предхешируйте на клиенте. Клиентски вычисленный хеш, отправленный на сервер — это новый пароль. Любой, кто читает базу, аутентифицируется. Хешируйте на сервере, точка. JWT этого не меняют; см. как декодировать токен JWT о том, что JWT аутентифицируют, а что — нет.

Бенчмарк на продакшен-железе, не на ноутбуке. Ноутбук Intel 13-го поколения с Argon2id m=19456, t=2, p=1 заканчивает примерно за 35 мс. Те же параметры на инстансе t3.small EC2 — ближе к 180 мс; на Raspberry Pi 4 — свыше 600 мс. Возьмите железо, на котором реально пойдёт продакшен, замерьте 1000 verifies, настройте по медиане. Разброс задержки логина от cold-start serverless-контейнеров тоже стоит измерить; cold start Lambda может добавить 200–800 мс, не связанных с хешированием.

FAQ

В чём разница между хешированием паролей и шифрованием?

Хеширование — одностороннее: вычисляете отпечаток фиксированной длины, который нельзя обратить, чтобы восстановить вход. Шифрование двустороннее: с правильным ключом расшифровываете обратно к оригиналу. Для паролей обязательно применяется хеширование, не шифрование. Сервер не должен иметь возможности восстановить пароль ни одного пользователя, чтобы утечка базы не превратилась в утечку учётных данных.

Почему нельзя просто использовать SHA-256 для паролей?

SHA-256 построен ради скорости. Современная GPU вычисляет 22 миллиарда хешей SHA-256 в секунду, поэтому 8-символьный пароль из нижнего регистра в утёкшей базе падает за минуты. Хешам паролей нужны три свойства, которых SHA-256 лишён: намеренно медленное выполнение, соль на запись и memory-hardness. Принцип компромисса тот же, что объяснён в гайдансе «не используйте MD5 для безопасности» в нашем генераторе хешей, а как атакующие превращают слабые хеши в plaintext — читайте в энтропия пароля.

Безопасен ли bcrypt в 2026-м?

Сам bcrypt не сломан. Установка ключа на основе Blowfish остаётся криптографически добротной. Изменилась модель угроз: GPU и ASIC делают отсутствие memory-hardness в bcrypt значимой слабостью на фоне Argon2id. Позиция OWASP в 2026-м: bcrypt приемлем для legacy-систем с cost ≥ 10, но новые проекты выбирают Argon2id.

Argon2i, Argon2d, Argon2id — какой использовать?

Используйте Argon2id. RFC 9106 указывает его как рекомендованный вариант для хеширования паролей. Argon2i — data-independent (безопасен по побочным каналам, но слабее против GPU-tradeoff атак). Argon2d — data-dependent (силён против GPU, но уязвим к побочным каналам кеш-таймингов). Argon2id — гибрид, дающий оба свойства.

Как выбрать параметры Argon2id для приложения?

Стартуйте с базовой OWASP: m=19456, t=2, p=1. Затем бенчмарк на продакшен-CPU и подстройка:

  1. Решите бюджет RAM на логин (скажем, 50 МБ при пиковой одновременности).
  2. Установите m в это значение или ниже.
  3. Прогоните argon2.hash() в цикле и замерьте wall-time.
  4. Поднимайте t, пока медиана не сядет между 100 и 500 мс.

Оставьте p=1, если не профилировали и не знаете, что многодорожечный параллелизм помогает вашему рантайму. Для высоконагруженных серверов аутентификации сдвиг в сторону большего t и меньшего m часто даёт лучший запас по RAM.

Что за лимит 72 байта в bcrypt и как обращаться с длинными парольными фразами?

bcrypt подаёт вход в установку ключа Blowfish, которая обрезает на 72 байтах. У 150-символьной парольной фразы та же безопасность, что и у её первых 72 байт; остальное игнорируется. Решение — предхешировать SHA-256 (32 байта) или SHA-512 (64 байта), закодировать base64, чтобы избежать NUL-байтов, и подать в bcrypt. У Argon2id и scrypt такого лимита нет; они принимают вход произвольной длины напрямую.

Можно ли мигрировать bcrypt на Argon2 без принудительного сброса паролей?

Да. Паттерн: храните оба алгоритма за колонкой password_algo, отправляйте verify в нужную библиотеку и при каждом успешном bcrypt-verify сразу же пере-хешируйте Argon2id и обновляйте запись. Активные пользователи мигрируют молча в обычной каденции своих логинов. Установите окно sunset 6–12 месяцев для неактивных аккаунтов, затем для записей, оставшихся на bcrypt, форсируйте сброс пароля. Тот же паттерн работает для любой миграции «алгоритм → алгоритм».

PBKDF2 — хороший выбор в 2026-м?

Только когда соответствие FIPS-140 диктует выбор: типично в федеральном правительстве, регулируемой медицине (HIPAA) и определённых финансовых системах. Используйте HMAC-SHA-256 как PRF минимум с 600 000 итераций. PBKDF2 не memory-hard, поэтому он сдаёт GPU-атакам быстрее Argon2id при эквивалентном бюджете задержки. Если FIPS не касается — выбирайте Argon2id и пропускайте лишнюю compliance-работу.


Ответ 2026 года по хешированию паролей короткий: по умолчанию — Argon2id с базовыми параметрами OWASP, фолбэк на scrypt при недоступности Argon2, bcrypt — только там, где требует legacy, PBKDF2 — для FIPS-связанных систем. Спарьте хеш с солью на запись (каждая современная библиотека делает это сама), app-уровневым pepper, хранящимся вне базы, и циклом re-hash, ведомым логином, который позволяет поднимать work factor по мере улучшения железа.

Сгенерируйте репрезентативный набор паролей генератором случайных паролей, забенчмаркайте verify-путь на продакшен-CPU и запишите параметры в файл констант, чтобы следующий инженер знал точно, что подкрутить в 2028-м. Полный контекст безопасности (TLS, управление сессиями, rate limiting, MFA) — в руководстве по основам веб-безопасности.

Похожие статьи

Все статьи