Хэш-функции и HMAC

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

В криптографических протоколах хэш-функции выполняют несколько ключевых задач:

  • контроль целостности данных
  • создание цифровых отпечатков сообщений
  • основа для построения HMAC
  • использование в цифровых подписях и токенах

В семействах алгоритмов, применяемых в JOSE, используются следующие хэш-функции:

  • SHA-256 (используется в HS256)
  • SHA-384 (HS384)
  • SHA-512 (HS512)

Каждая из них относится к семейству SHA-2 и отличается длиной выходного хэша и уровнем криптостойкости.


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

Для безопасного использования в протоколах аутентификации хэш-функция должна удовлетворять следующим требованиям:

Детерминированность

Один и тот же вход всегда даёт одинаковый результат.

Быстрота вычисления

Хэш должен вычисляться эффективно даже для больших данных.

Необратимость

По значению хэша невозможно восстановить исходное сообщение.

Устойчивость к коллизиям

Практически невозможно найти два разных входа, дающих одинаковый хэш.

Avalanche effect

Малое изменение входа радикально меняет результат.

Эти свойства делают хэш-функции фундаментом для построения HMAC.


HMAC как механизм аутентификации сообщений

HMAC (Hash-based Message Authentication Code) — это механизм, который использует хэш-функцию и секретный ключ для проверки целостности и подлинности сообщения.

Формально HMAC вычисляется как:

(K, m) = H((K opad) ;|; H((K ipad) ;|; m))

Где:

  • K — секретный ключ
  • m — сообщение
  • H — криптографическая хэш-функция
  • opad / ipad — фиксированные константы
  • — операция XOR
  • | — конкатенация

Свойства HMAC

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

HMAC в стандарте JOSE

JOSE (JSON Object Signing and Encryption) определяет набор алгоритмов для подписи и шифрования JSON-структур. В части JWS (JSON Web Signature) HMAC используется в симметричных алгоритмах:

  • HS256 → HMAC + SHA-256
  • HS384 → HMAC + SHA-384
  • HS512 → HMAC + SHA-512

Эти алгоритмы обозначаются как:

  • HS256
  • HS384
  • HS512

Принцип работы:

  1. создаётся подпись на основе заголовка и payload
  2. используется общий секретный ключ
  3. результат кодируется в Base64URL
  4. подпись добавляется в JWT

Использование HMAC в библиотеке jose

Библиотека jose реализует современные стандарты JOSE с использованием Web Crypto API или Node.js crypto.

Подписание JWT с HS256

import { SignJWT } from 'jose'

const secret = new TextEncoder().encode('super-secret-key')

const jwt = await new SignJWT({ userId: 123 })
  .setProtectedHeader({ alg: 'HS256' })
  .setIssuedAt()
  .setExpirationTime('2h')
  .sign(secret)

В этом примере:

  • используется HMAC-SHA256
  • секретный ключ симметричный
  • подпись формируется автоматически библиотекой

Проверка JWT с HMAC

import { jwtVerify } from 'jose'

const secret = new TextEncoder().encode('super-secret-key')

const { payload, protectedHeader } = await jwtVerify(token, secret, {
  algorithms: ['HS256']
})

При проверке выполняется:

  • вычисление HMAC от заголовка и payload
  • сравнение с подписью токена
  • возврат payload при совпадении

Ключи в HMAC и требования безопасности

Качество безопасности HMAC напрямую зависит от секретного ключа.

Рекомендации к ключам:

  • длина не менее длины выхода хэш-функции (например, 32 байта для SHA-256)
  • использование криптографически случайных значений
  • отсутствие предсказуемости (не использовать строки типа “password123”)
  • регулярная ротация ключей

В Node.js безопасный ключ создаётся так:

import { randomBytes } from 'crypto'

const secret = randomBytes(32)

Отличие HMAC от обычного хэша

Обычная хэш-функция:

  • не использует ключ
  • подходит только для проверки целостности без аутентификации

HMAC:

  • использует секретный ключ
  • защищает от подмены данных атакующим
  • применяется в JWT подписи

Алгоритмы HS256, HS384, HS512 в деталях

HS256

  • SHA-256
  • 256-битный хэш
  • наиболее распространённый вариант

HS384

  • SHA-384
  • более длинный хэш
  • повышенная криптостойкость

HS512

  • SHA-512
  • максимальная длина хэша в семействе HS
  • используется в системах с повышенными требованиями к безопасности

Внутреннее устройство подписи JWT через HMAC

Процесс формирования подписи:

  1. сериализация header и payload
  2. Base64URL кодирование
  3. объединение через точку:
base64Url(header) + "." + base64Url(payload)
  1. вычисление HMAC от строки
  2. Base64URL кодирование результата

Ошибки при использовании HMAC в JOSE

Использование слабого секрета

Короткие или предсказуемые ключи делают систему уязвимой к перебору.

Несовместимые алгоритмы

Указание alg: HS256 при проверке токена, подписанного другим алгоритмом, может привести к ошибкам или уязвимостям.

Повторное использование ключей в разных системах

Один секрет не должен использоваться для разных сервисов.

Отсутствие ограничения алгоритмов

jwtVerify(token, secret, {
  algorithms: ['HS256']
})

Игнорирование этого параметра может привести к атакам по смене алгоритма.


Сравнение HMAC и цифровых подписей RSA/ECDSA

HMAC (симметричный подход):

  • один секретный ключ
  • высокая скорость
  • сложность распределения ключей

RSA/ECDSA (асимметричный подход):

  • пара ключей (public/private)
  • удобство в распределённых системах
  • более высокая вычислительная стоимость

Роль хэш-функций внутри JOSE

Хэш-функции используются не только в HMAC, но и в:

  • формировании подписей RSA-PSS
  • ECDSA-алгоритмах
  • вычислении digest в JWE (шифрование)
  • проверке целостности заголовков JWT

Использование Web Crypto API в jose

В современных версиях jose используется Web Crypto API:

  • crypto.subtle.sign
  • crypto.subtle.verify

Это обеспечивает:

  • ускорение операций
  • аппаратное ускорение на уровне ОС
  • отсутствие сторонних зависимостей

Пример ручной работы с ключом HMAC

import { importJWK, SignJWT } from 'jose'

const jwk = {
  kty: 'oct',
  k: 'c3VwZXItc2VjcmV0LWtleQ',
  alg: 'HS256'
}

const key = await importJWK(jwk, 'HS256')

const token = await new SignJWT({ role: 'admin' })
  .setProtectedHeader({ alg: 'HS256' })
  .setIssuedAt()
  .sign(key)

Влияние качества хэш-функции на безопасность JWT

Сильные хэш-функции обеспечивают:

  • устойчивость к атаке подбора
  • защиту от модификации payload
  • надёжность HMAC-подписей

Слабые или устаревшие хэш-функции (MD5, SHA-1) не применяются в JOSE из-за известных уязвимостей.


Практическая модель угроз

При использовании HMAC в JWT основная модель атак включает:

  • brute-force ключа
  • replay-атаки (повтор токена)
  • подмена алгоритма (alg confusion)
  • утечка секретного ключа

Каждая из этих угроз напрямую связана с качеством реализации хэш-функций и управления секретами.