Криптографическая хэш-функция преобразует произвольный входной набор данных в фиксированную строку байтов, называемую хэшем. Основное свойство таких функций — необратимость: восстановить исходные данные по хэшу вычислительно невозможно.
В криптографических протоколах хэш-функции выполняют несколько ключевых задач:
В семействах алгоритмов, применяемых в JOSE, используются следующие хэш-функции:
Каждая из них относится к семейству SHA-2 и отличается длиной выходного хэша и уровнем криптостойкости.
Для безопасного использования в протоколах аутентификации хэш-функция должна удовлетворять следующим требованиям:
Один и тот же вход всегда даёт одинаковый результат.
Хэш должен вычисляться эффективно даже для больших данных.
По значению хэша невозможно восстановить исходное сообщение.
Практически невозможно найти два разных входа, дающих одинаковый хэш.
Малое изменение входа радикально меняет результат.
Эти свойства делают хэш-функции фундаментом для построения HMAC.
HMAC (Hash-based Message Authentication Code) — это механизм, который использует хэш-функцию и секретный ключ для проверки целостности и подлинности сообщения.
Формально HMAC вычисляется как:
(K, m) = H((K opad) ;|; H((K ipad) ;|; m))
Где:
JOSE (JSON Object Signing and Encryption) определяет набор алгоритмов для подписи и шифрования JSON-структур. В части JWS (JSON Web Signature) HMAC используется в симметричных алгоритмах:
Эти алгоритмы обозначаются как:
HS256HS384HS512Принцип работы:
Библиотека jose реализует современные стандарты JOSE с
использованием Web Crypto API или Node.js crypto.
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)
В этом примере:
import { jwtVerify } from 'jose'
const secret = new TextEncoder().encode('super-secret-key')
const { payload, protectedHeader } = await jwtVerify(token, secret, {
algorithms: ['HS256']
})
При проверке выполняется:
Качество безопасности HMAC напрямую зависит от секретного ключа.
В Node.js безопасный ключ создаётся так:
import { randomBytes } from 'crypto'
const secret = randomBytes(32)
Обычная хэш-функция:
HMAC:
Процесс формирования подписи:
base64Url(header) + "." + base64Url(payload)
Короткие или предсказуемые ключи делают систему уязвимой к перебору.
Указание alg: HS256 при проверке токена, подписанного
другим алгоритмом, может привести к ошибкам или уязвимостям.
Один секрет не должен использоваться для разных сервисов.
jwtVerify(token, secret, {
algorithms: ['HS256']
})
Игнорирование этого параметра может привести к атакам по смене алгоритма.
HMAC (симметричный подход):
RSA/ECDSA (асимметричный подход):
Хэш-функции используются не только в HMAC, но и в:
В современных версиях jose используется Web Crypto
API:
crypto.subtle.signcrypto.subtle.verifyЭто обеспечивает:
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)
Сильные хэш-функции обеспечивают:
Слабые или устаревшие хэш-функции (MD5, SHA-1) не применяются в JOSE из-за известных уязвимостей.
При использовании HMAC в JWT основная модель атак включает:
Каждая из этих угроз напрямую связана с качеством реализации хэш-функций и управления секретами.