HMAC (Hash-based Message Authentication Code) в Web Crypto API
реализуется через интерфейс SubtleCrypto и используется для
создания симметричных ключей, предназначенных для проверки целостности и
подлинности данных на основе криптографической хэш-функции.
В отличие от обычных хэш-функций, HMAC включает секретный ключ, что делает результат вычисления защищённым от подмены без знания этого ключа.
В Web Crypto API HMAC определяется через объект алгоритма:
{
name: "HMAC",
hash: { name: "SHA-256" }
}
Ключевым параметром является hash, который определяет
используемую хэш-функцию. Поддерживаемые варианты:
Для создания HMAC-ключа используется метод:
crypto.subtle.generateKey(algorithm, extractable, keyUsages)
const key = await crypto.subtle.generateKey(
{
name: "HMAC",
hash: { name: "SHA-256" }
},
true,
["sign", "verify"]
);
Описывает тип ключа и параметры хэширования:
{
name: "HMAC",
hash: { name: "SHA-256" }
}
Значение name строго фиксировано как
"HMAC".
Булево значение, определяющее возможность экспорта ключа:
true — ключ можно экспортировать через
exportKeyfalse — ключ остаётся внутри WebCrypto и не может быть
извлечёнfalse
На практике для продакшн-систем часто выбирается false,
чтобы минимизировать риск утечки ключа.
Определяет, какие операции разрешены с ключом:
"sign" — создание HMAC подписи"verify" — проверка подписи["sign", "verify"]
Если указать лишние или отсутствующие значения, браузер выбросит
InvalidAccessError.
async function createHmacKey() {
const key = await crypto.subtle.generateKey(
{
name: "HMAC",
hash: { name: "SHA-256" }
},
false,
["sign", "verify"]
);
return key;
}
generateKey возвращает объект типа
CryptoKey.
Для HMAC он имеет следующие свойства:
type: "secret"extractable: true | falsealgorithm: { name: "HMAC", hash: ... }usages: ["sign", "verify"]После генерации ключа он используется через:
async function signData(key, data) {
const encoder = new TextEncoder();
const encoded = encoder.encode(data);
const signature = await crypto.subtle.sign(
"HMAC",
key,
encoded
);
return signature;
}
async function verifySignature(key, signature, data) {
const encoder = new TextEncoder();
const encoded = encoder.encode(data);
const result = await crypto.subtle.verify(
"HMAC",
key,
signature,
encoded
);
return result;
}
HMAC использует симметричный ключ, который должен оставаться
конфиденциальным. Даже в браузере он хранится в виде
CryptoKey, недоступного для прямого чтения.
Если extractable установлен в false, ключ
невозможно получить в виде строки или массива байт.
Попытка экспорта:
crypto.subtle.exportKey("raw", key);
приведёт к ошибке InvalidAccessError.
HMAC-ключ жёстко связан с выбранной хэш-функцией. Ключ, созданный для SHA-256, нельзя использовать с SHA-512 без повторной генерации.
Если ключ создан с extractable: true, его можно
экспортировать:
const rawKey = await crypto.subtle.exportKey("raw", key);
Результат — ArrayBuffer.
Импорт используется для восстановления ключа из внешнего источника:
const key = await crypto.subtle.importKey(
"raw",
keyData,
{
name: "HMAC",
hash: { name: "SHA-256" }
},
false,
["sign", "verify"]
);
HMAC часто применяется для проверки неизменности данных при передаче:
В браузере HMAC может использоваться для:
Пример формирования подписи:
const data = "userId=42&action=login";
const signature = await signData(key, data);
Далее подпись передаётся вместе с запросом и проверяется на сервере.
Возникает при неправильном названии алгоритма:
name: "hmac" // ошибка
Правильно:
name: "HMAC"
Ошибка появляется, если хэш не поддерживается:
hash: { name: "MD5" } // не поддерживается
Если не указать "sign" или "verify",
операции будут недоступны:
[] // приведёт к невозможности использования ключа
generateKeysignverifyextractable: false)