Slovník pojmů
HMAC
HMAC dokládá pravost a integritu zprávy mezi stranami se společným tajemstvím. Nešifruje obsah ani sám nezabrání replay útoku.
Stručná definice
Podpis zprávy pomocí společného tajemství.
Odesílatel a příjemce znají stejné tajemství. Odesílatel z dat stanovených protokolem spočítá HMAC a výsledek odešle v hlavičce. Příjemce z původních dat znovu spočítá očekávanou hodnotu a porovná ji s podpisem. Shoda říká, že data vytvořil držitel stejného tajemství a cestou se nezměnila.
HMAC je message authentication code, ne asymetrický digitální podpis. Každý držitel tajemství umí zprávu vytvořit i ověřit, takže HMAC neposkytuje nezávislý důkaz třetí straně. Nechrání důvěrnost payloadu ani bez timestampu, nonce nebo ID nezastaví replay dříve platné zprávy.
Použití
Kdy aplikace potřebuje ověřit původ zprávy
Hodí se tam, kde dvě strany bezpečně sdílejí tajemství a potřebují ověřit konkrétní požadavek.
- webhook od platební brány, marketplace nebo dopravce
- server-to-server HTTP požadavek uvnitř integračního toku
- podpis callbacku, kde protokol přesně definuje podepisované hlavičky a tělo
- ověření integrity vnitřního požadavku spolu s HTTPS a autentizací
Praktický příklad
Ověření podpisu webhooku v PHP
Poskytovatel v tomto zjednodušeném příkladu podepisuje řetězec timestamp.rawBody algoritmem HMAC-SHA-256 a výsledek posílá hexadecimálně v hlavičce. Reálný endpoint musí použít přesné hlavičky, oddělovač, encoding i pravidla poskytovatele.
Tajemství přichází z bezpečné konfigurace. Po ověření následuje uložení ID události s unikátním omezením; samotný HMAC nebrání druhému doručení stejné platné zprávy.
$rawBody = $request->getContent();
$timestamp = (string) $request->headers->get('X-Webhook-Timestamp', '');
$providedSignature = (string) $request->headers->get('X-Webhook-Signature', '');
if (!preg_match('/^\d+\z/', $timestamp) || abs(time() - (int) $timestamp) > 300) {
throw new AccessDeniedHttpException('Neplatný webhook.');
}
// Podoba vstupu musí přesně odpovídat dokumentaci poskytovatele.
$signingInput = $timestamp . '.' . $rawBody;
$expectedSignature = hash_hmac('sha256', $signingInput, $webhookSecret);
if (!hash_equals($expectedSignature, $providedSignature)) {
throw new AccessDeniedHttpException('Neplatný webhook.');
}
Jak funguje
Od raw požadavku po bezpečné přijetí webhooku
Tvar zprávy a kódování podpisu určuje poskytovatel; bez jeho dokumentace jej nelze bezpečně domýšlet.
- Sestavení vstupu Protokol stanoví raw body, timestamp, ID události nebo jejich spojení. Obě strany musí použít stejné bajty a pořadí.
- Výpočet podpisu Odesílatel spočítá HMAC z tohoto vstupu a tajemství. Podpis odešle například jako hex nebo Base64 v určené hlavičce.
- Převzetí bez změny Příjemce nejprve načte raw body a relevantní hlavičky. JSON nesmí před ověřením znovu serializovat ani normalizovat.
- Ověření a čerstvost Vypočte očekávaný HMAC, porovná jej constant-time funkcí a podle kontraktu ověří timestamp, nonce nebo ID události.
- Trvalý účinek Až po ověření uloží událost s ochranou proti duplicitě a práci předá do fronty.
Důležité pojmy
Tajemství, data a protokol musí souhlasit.
Bezpečnost nezávisí jen na algoritmu, ale i na podepisovaných datech a správě tajemství.
Shared secret
Tajemství je klíč pro výpočet i ověření HMAC. Není to uživatelské heslo ani veřejný API klíč; patří do bezpečné konfigurace, ne do logu či repozitáře.
Raw payload a canonicalizace
Podpis platí pro přesně určené bajty. I stejné JSON hodnoty mohou mít jiný zápis mezer, pořadí klíčů nebo escapování. Canonicalizaci určuje protokol.
Algoritmus a kódování
HMAC-SHA-256 je častá volba, ale algoritmus i formát podpisu určuje kontrakt. Aplikace nepřijímá algoritmus ani URL klíče z hlavičky.
Constant-time porovnání
Výsledek se neporovnává běžným == ani ===. V PHP hash_equals() omezuje únik podle místa první neshody; očekávaná hodnota je prvním argumentem.
Replay a rotace
Platný podpis lze přehrát. Časové okno, event ID a trvalá deduplikace řeší jiný problém než HMAC. Staré tajemství při rotaci musí mít omezenou platnost.
Vztah k podobným pojmům
HMAC není šifrování ani univerzální přihlášení.
Pojmy se v integračním HTTP toku potkávají, ale poskytují odlišné bezpečnostní vlastnosti.
- Webhook
- Webhook často používá HMAC pro ověření odesílatele, ale stále potřebuje deduplikaci.
- JWT
- JWT je formát tokenu s jiným validačním kontextem. Webhookový HMAC není automaticky JWT.
- OAuth 2.0
- OAuth pracuje s delegovanou autorizací a tokeny. HMAC podpis zprávy ho nenahrazuje.
- HTTPS/TLS
- TLS chrání přenos; HMAC ověřuje podepsaná data mezi držiteli tajemství. Pro veřejný endpoint je obvykle potřeba obojí.
Výhody a omezení
Jednoduché ověření za cenu sdíleného tajemství.
Přínosy
- integrita a ověření odesílatele bez vlastního PKI
- rychlý výpočet nad přesně definovaným vstupem
- vhodné pro webhooky a server-to-server integrace
Rizika
- únik shared secretu dovolí vytvářet platné podpisy
- HMAC nešifruje payload ani neprokazuje konkrétního držitele tajemství
- neshoda v raw datech, encodingu nebo timestampu způsobí zamítnutí
- bez replay ochrany může platná zpráva působit opakovaně
Hranice použití
Použít tehdy, když obě strany umí tajemství bezpečně spravovat.
HMAC se hodí pro integrační kontrakt s předem známým poskytovatelem a přesně popsaným podpisem. Příjemce musí bezpečně spravovat secret, rotaci i dohledatelnost odmítnutých požadavků. Podpis doplňuje ochranu transportu a autorizaci následných kroků.
Nevhodný je tam, kde příjemce potřebuje ověřit podpis bez možnosti zprávu sám vytvořit; tehdy se hodí asymetrický podpis s veřejným ověřovacím klíčem. HMAC také není mechanismus pro ukládání hesel, pro něž slouží záměrně pomalé funkce.
Na co myslet
Ověřit nejprve data, pak jejich businessový význam.
Bezpečný podpis je součást příjmového toku, ne jen podmínka v controlleru.
- algoritmus, signovací vstup a formát podpisu přesně podle dokumentace poskytovatele
- raw body před JSON dekódováním a porovnání přes hash_equals()
- secret v bezpečné konfiguraci, rotace a nulové logování hodnot
- časové okno, event ID a databázová deduplikace pro omezení replay a retry
- obecná chyba pro nedůvěryhodný požadavek a testy změněného payloadu
Časté otázky
Co HMAC skutečně zaručuje
Šifruje HMAC payload?
Ne. HMAC ověřuje integritu a držitele tajemství. Obsah chrání HTTPS/TLS nebo šifrování.
Stačí porovnat podpis pomocí ===?
Ne. V PHP je vhodná hash_equals(), určená pro porovnání bezpečné vůči timing útokům.
Proč musí endpoint číst raw body?
Podpis se často počítá nad původními bajty. Opětovné zakódování JSONu může změnit jeho výsledný HMAC.
Zastaví HMAC replay útok?
Ne. Platný požadavek lze poslat znovu. Ochranu doplňuje timestamp, nonce nebo trvale uložené event ID.
Je HMAC vhodný pro ukládání hesel?
Ne. Pro hesla slouží adaptivní hashovací funkce; HMAC ověřuje zprávu sdíleným klíčem.
Jak řeším API a integrační hranice
Příjem externích událostí navrhuji s ověřením.
U webhooků a API integrací řeším ověření, retry, timeouty i businessová pravidla.