HMAC (Hash-based Message Authentication Code) представляет собой
механизм проверки целостности и подлинности сообщения с использованием
криптографической хеш-функции и общего секретного ключа. В Web Crypto
API этот механизм реализуется через алгоритм HMAC,
встроенный в интерфейс SubtleCrypto.
Основная идея заключается в том, что отправитель и получатель используют один и тот же секретный ключ. На основе этого ключа и сообщения вычисляется подпись. Любое изменение данных приводит к изменению подписи, что делает подделку обнаружимой.
В отличие от обычных хеш-функций, HMAC защищён от атак с подбором коллизий и расширения сообщения благодаря использованию секретного ключа.
Рассматривается типичная ситуация:
Цель HMAC — гарантировать:
Работа с HMAC в браузере осуществляется через
crypto.subtle, где доступны операции:
Ключевой объект — CryptoKey, содержащий секретный ключ
HMAC.
Создание ключа выполняется с использованием
generateKey.
const key = await crypto.subtle.generateKey(
{
name: "HMAC",
hash: { name: "SHA-256" }
},
true,
["sign", "verify"]
);
Разбор параметров:
name: "HMAC" — использование алгоритма HMAChash: { name: "SHA-256" } — хеш-функция внутри
HMACtrue — возможность экспорта ключа["sign", "verify"] — назначение ключаИспользование SHA-256 является наиболее распространённым вариантом, обеспечивающим баланс между скоростью и криптографической стойкостью.
Web Crypto API работает с бинарными данными. Строки необходимо
преобразовывать в ArrayBuffer.
function encode(data) {
return new TextEncoder().encode(data);
}
Подпись формируется методом subtle.sign.
const data = encode("сообщение для защиты");
const signature = await crypto.subtle.sign(
"HMAC",
key,
data
);
Результатом является ArrayBuffer, содержащий бинарную
подпись.
Для удобства хранения или передачи часто используется преобразование в Base64:
function toBase64(buffer) {
return btoa(String.fromCharCode(...new Uint8Array(buffer)));
}
Проверка выполняется методом subtle.verify.
const isValid = await crypto.subtle.verify(
"HMAC",
key,
signature,
data
);
Результат:
true — данные не изменены и подпись корректнаfalse — данные или подпись подделаныВажно, что проверка выполняется на уровне Web Crypto API и устойчива к тайминговым атакам, так как сравнение подписи происходит в постоянное время.
function encode(data) {
return new TextEncoder().encode(data);
}
function toBase64(buffer) {
return btoa(String.fromCharCode(...new Uint8Array(buffer)));
}
function fromBase64(base64) {
const binary = atob(base64);
return Uint8Array.from(binary, c => c.charCodeAt(0));
}
const key = await crypto.subtle.generateKey(
{
name: "HMAC",
hash: { name: "SHA-256" }
},
true,
["sign", "verify"]
);
const message = "важные данные";
const encoded = encode(message);
const signatureBuffer = await crypto.subtle.sign(
"HMAC",
key,
encoded
);
const signatureBase64 = toBase64(signatureBuffer);
const receivedData = encode(message);
const receivedSignature = fromBase64(signatureBase64);
const valid = await crypto.subtle.verify(
"HMAC",
key,
receivedSignature,
receivedData
);
Для хранения или передачи ключ может быть экспортирован.
Экспорт:
const rawKey = await crypto.subtle.exportKey("raw", key);
Импорт:
const importedKey = await crypto.subtle.importKey(
"raw",
rawKey,
{
name: "HMAC",
hash: { name: "SHA-256" }
},
true,
["sign", "verify"]
);
Экспорт в формате raw представляет собой бинарный массив
секретного ключа.
Web Crypto API поддерживает несколько вариантов хеша внутри HMAC:
SHA-256 используется как базовый вариант в большинстве веб-приложений.
HMAC в Web Crypto API имеет ряд особенностей:
CryptoKey, недоступного напрямую в
памяти JavaScriptAPI не принимает строки напрямую. Любые данные должны быть
преобразованы в ArrayBuffer.
Один и тот же ключ не должен использоваться в разных контекстах без разделения области применения. В противном случае возможна утечка безопасности между подсистемами.
Экспортированный ключ в формате raw должен храниться с
тем же уровнем защиты, что и пароли или токены.
Метод verify возвращает логическое значение, и его
необходимо использовать как единственный источник истины при проверке
целостности данных.
HMAC часто путают с асимметричной подписью, но архитектурно они различаются:
HMAC применяется там, где обе стороны доверяют общему секрету.
Web Crypto API реализует HMAC на уровне нативных криптографических библиотек браузера, что обеспечивает:
Ограничением является невозможность синхронного выполнения операций —
все методы возвращают Promise.
HMAC используется для:
Типичный поток работы:
Любое изменение:
приводит к изменению HMAC. Проверка завершится отрицательным результатом без указания причины, что предотвращает утечку информации о структуре ключа.
HMAC в Web Crypto API обеспечивает криптографическую целостность данных при условии:
Механизм остаётся устойчивым к подделке сообщений при нарушении канала передачи, сохраняя целостность и подлинность информации на уровне криптографического протокола браузера.