Лаборатория кодера

Справочник · Данные и форматы

Хеширование: какие функции для чего подходят

Свойства криптографических хешей, сравнение MD5, SHA-1, SHA-2, SHA-3 и BLAKE, хранение паролей, HMAC и проверка файлов.

Обновлено · 5 мин чтения

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

Свойства криптографического хеша

СвойствоЧто значитЗачем нужно
необратимостьпо хешу нельзя найти входхеш не раскрывает данные
стойкость ко второму прообразупо данному входу нельзя подобрать другой с тем же хешемнельзя подменить файл
стойкость к коллизиямнельзя найти любые два входа с одинаковым хешемподписи и сертификаты
лавинный эффектизменение одного бита меняет около половины бит хешапохожие входы не выдают себя

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

text
sha256("hello")  = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
sha256("hello.") = 1589999b0ca6ef8814283026a9f166d51c70a910671c3d44049755f07f2eb910

Сравнение алгоритмов

АлгоритмДлина, битHex-символовСтатус
MD512832сломан: коллизии находятся за секунды
SHA-116040сломан: практическая коллизия показана в 2017 году
SHA-22422456надёжен, редко нужен
SHA-25625664надёжен, стандарт по умолчанию
SHA-38438496надёжен
SHA-512512128надёжен, на 64-битных процессорах часто быстрее SHA-256
SHA3-25625664надёжен, другая внутренняя конструкция
BLAKE2bдо 512до 128надёжен, быстрый
BLAKE3256 и больше64надёжен, очень быстрый, параллелится

MD5 и SHA-1 до сих пор годятся там, где нет злоумышленника: найти случайно испорченный при копировании файл, ключ для кэша, поиск дубликатов. Для подписей, сертификатов и всего, где кто-то может специально подобрать данные, — только SHA-256 и новее.

Проверка файлов

bash
sha256sum ubuntu.iso                       # посчитать
sha256sum -c SHA256SUMS --ignore-missing   # сверить со списком
shasum -a 256 file.zip                     # то же на macOS
md5sum file                                 # быстро найти битую копию
b2sum file                                  # BLAKE2b
certutil -hashfile file.zip SHA256         # Windows
Get-FileHash file.zip -Algorithm SHA256    # PowerShell

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

Хранение паролей

Обычные хеш-функции созданы быстрыми. Для паролей это плохо: видеокарта перебирает миллиарды вариантов SHA-256 в секунду, и короткий пароль из утёкшей базы восстанавливается за минуты. Поэтому для паролей используют специальные медленные функции с солью.

ФункцияСтатусПараметры
Argon2idрекомендуется первойпамять, число проходов, параллелизм
scryptхороший выборN, r, p — память и время
bcryptнадёжен, широко поддерживаетсястоимость 10–12 и выше; учитывает только первые 72 байта пароля
PBKDF2-SHA256допустим, если других нетот 600 000 итераций
SHA-256, MD5, с солью или безнельзяслишком быстрые

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

python
# pip install argon2-cffi
from argon2 import PasswordHasher
ph = PasswordHasher()
stored = ph.hash("correct horse battery staple")   # в строке уже есть соль и параметры
ph.verify(stored, "correct horse battery staple")  # True или исключение

Длинный случайный пароль надёжнее любых хитростей с хешированием. Его можно сделать в генераторе паролей.

HMAC: хеш с ключом

Если нужно убедиться, что сообщение пришло от того, кто знает секрет, используют HMAC. Его считают для вебхуков, подписанных ссылок, токенов вроде JWT с алгоритмом HS256.

bash
printf '%s' '{"event":"paid"}' | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET"
python
import hmac, hashlib
sig = hmac.new(secret, body, hashlib.sha256).hexdigest()
hmac.compare_digest(sig, received_sig)   # сравнение без утечки по времени

Некриптографические хеши

Для хеш-таблиц, шардирования и контрольных сумм нужна скорость, а не стойкость.

ФункцияГде встречается
CRC32zip, PNG, Ethernet: ловит случайные ошибки передачи
xxHashбыстрая проверка больших файлов, базы данных
MurmurHash, SipHashхеш-таблицы в языках программирования
FNV-1aпростые случаи, легко написать самому

Их можно подобрать специально, поэтому для безопасности они не годятся.

Частые ошибки

  • Хеш — не шифрование. Его нельзя «расшифровать». Если сервис может прислать вам ваш пароль, он хранит его не хешем.
  • Хеш — не Base64. Base64 обратим и ничего не скрывает, это просто запись байт текстом.
  • Хеш текста зависит от кодировки и переводов строк. Строка с \r\n и \n даст разные хеши, как и одна строка в UTF-8 и Windows-1251. При сравнении хешей между системами сначала договоритесь о байтах.
  • echo добавляет перевод строки. echo hello | sha256sum считает хеш от hello\n. Используйте printf '%s' hello или echo -n.