Generator HMAC

Oblicz HMAC tekstu, bajtów hex lub pliku z kluczem tajnym przy użyciu SHA-256, SHA-384, SHA-512, SHA-1 lub MD5 i porównaj wynik z podpisem webhooka lub API. Żadne dane nie opuszczają przeglądarki.

Działa w całości w przeglądarce. Nic nie jest wysyłane.

Jak używać

  1. Wybierz algorytm. Domyślnie wybrany jest HMAC-SHA256, którego używa większość webhooków i interfejsów API.
  2. Wpisz „Klucz tajny” i ustaw „Format klucza” na „Tekst” (odczytywany jako UTF-8), „Hex” lub „Base64”. Wybierz „Hex” lub „Base64”, gdy klucz to surowe bajty, a nie ciąg przypominający hasło.
  3. Wpisz lub wklej wiadomość, przełącz wejście na „Hex”, aby podać surowe bajty, albo kliknij „Otwórz plik”. HMAC aktualizuje się na bieżąco podczas pisania.
  4. W polu „Wyjście jako” wybierz „hex (małe litery)”, „HEX (wielkie litery)” lub „Base64” i skopiuj wynik albo wklej otrzymany podpis w polu „Porównaj z”, aby zobaczyć komunikat „Zgadza się” lub „Nie zgadza się”.

Jak działa HMAC

HMAC (hash-based message authentication code, czyli kod uwierzytelniania wiadomości oparty na funkcji hashującej, RFC 2104) łączy kryptograficzną funkcję hashującą z kluczem tajnym. Tylko ktoś, kto zna klucz, może obliczyć prawidłową wartość dla danej wiadomości, więc zgodny HMAC dowodzi jednocześnie dwóch rzeczy: wiadomość nie została zmieniona i pochodzi od posiadacza klucza.

Konstrukcja ma postać H((K ⊕ opad) ‖ H((K ⊕ ipad) ‖ message)). Klucz dłuższy niż rozmiar bloku funkcji hashującej (64 bajty dla MD5, SHA-1 i SHA-256, 128 dla SHA-384 i SHA-512) jest najpierw hashowany, potem dopełniany zerami do tego rozmiaru, a następnie poddawany operacji XOR z ipad (bajty 0x36) na potrzeby wewnętrznego hasha obliczanego z wiadomości oraz z opad (bajty 0x5c) na potrzeby zewnętrznego hasha obliczanego z wyniku wewnętrznego. Naiwna konstrukcja SHA-256(key ‖ message) nie ma zewnętrznego hasha, więc każdy, kto zobaczy jeden taki kod, może dopisać dane do wiadomości i bez znajomości klucza obliczyć nowy prawidłowy kod (atak przedłużenia wiadomości, ang. length extension).

Wynik ma taką samą długość jak wynik bazowej funkcji hashującej: dla HMAC-SHA256 to 32 bajty, czyli 64 znaki hex. RFC 2104 zaleca klucz co najmniej tej długości, a odpowiednie klucze tworzy generator losowego Base64.

Gdzie używa się podpisów HMAC

  • Webhooki GitHub. Nagłówek X-Hub-Signature-256 to sha256=, po którym następuje HMAC-SHA256 w postaci hex obliczony z surowej treści żądania, z sekretem webhooka jako kluczem. Całą wartość nagłówka można wkleić w pole „Porównaj z”; prefiks sha256= jest ignorowany.
  • Webhooki Stripe. Nagłówek Stripe-Signature zawiera znacznik czasu t i podpis v1: HMAC-SHA256 w postaci hex obliczony ze znacznika czasu, kropki i surowej treści, z sekretem punktu końcowego (whsec_...) użytym jako klucz tekstowy.
  • Webhooki Shopify. X-Shopify-Hmac-Sha256 zawiera HMAC-SHA256 surowej treści w Base64, obliczony z sekretem klienta aplikacji (client secret) jako kluczem, więc wybierz wyjście „Base64” albo wklej wartość nagłówka w pole „Porównaj z”.
  • AWS Signature Version 4. Klucz podpisujący powstaje przez łańcuch operacji HMAC-SHA256: najpierw obliczany jest HMAC daty z kluczem AWS4 połączonym z tajnym kluczem dostępu, potem regionu, usługi i aws4_request, za każdym razem z poprzednim wynikiem jako kluczem. Ustaw „Format klucza” na „Hex”, aby przekazać wynik jednego kroku do następnego.
  • JSON Web Token. HS256, HS384 i HS512 to HMAC-SHA256, -384 i -512 obliczone z zakodowanego nagłówka, kropki i zakodowanego ładunku. Trzecia część tokena to ten HMAC w Base64 bezpiecznym dla URL, który pole „Porównaj z” przyjmuje bez zmian. Całe tokeny weryfikuje dekoder JWT.

Zawsze obliczaj HMAC z surowej treści dokładnie w takiej postaci, w jakiej została odebrana. Parsowanie JSON i ponowna serializacja zmieniają odstępy lub kolejność kluczy, a nawet jeden dodatkowy znak nowego wiersza daje zupełnie inny HMAC.

HMAC w kodzie

# Python
import hmac, hashlib
sig = hmac.new(b'key', b'message', hashlib.sha256).hexdigest()
hmac.compare_digest(sig, received)        # porównanie w stałym czasie

// Node.js
const crypto = require('crypto');
const sig = crypto.createHmac('sha256', 'key').update('message').digest('hex');
// timingSafeEqual zgłasza błąd, gdy długości się różnią, więc najpierw je sprawdź
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(received));

// PHP: wiadomość podaje się przed kluczem
$sig = hash_hmac('sha256', 'message', 'key');
hash_equals($sig, $received);

# OpenSSL: klucz tekstowy, a potem ten sam klucz podany jako hex
printf '%s' 'message' | openssl dgst -sha256 -hmac 'key'
printf '%s' 'message' | openssl dgst -sha256 -mac HMAC -macopt hexkey:6b6579

# Wektor testowy: klucz "key", wiadomość "The quick brown fox jumps over the lazy dog"
# HMAC-SHA256 = f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8

Weryfikując podpis we własnym kodzie, używaj porównania w stałym czasie, takiego jak w przykładach powyżej. Zwykłe == kończy porównanie na pierwszym różniącym się znaku, a ta różnica w czasie wykonania może pozwolić atakującemu odgadnąć prawidłowy podpis bajt po bajcie. W schematach ze znacznikiem czasu, takich jak schemat Stripe, odrzucaj też żądania, których znacznik czasu jest starszy niż kilka minut – to blokuje ataki powtórzeniowe.

Najczęściej zadawane pytania

Czy HMAC-MD5 i HMAC-SHA1 są nadal bezpieczne?

Ataki kolizyjne łamią MD5 i SHA-1 jako zwykłe funkcje hashujące, ale nie dają praktycznego sposobu na sfałszowanie HMAC, który zależy od innych właściwości funkcji hashującej oraz od klucza tajnego (HMAC-MD5 omawia RFC 6151). Integracje, które ich wymagają, np. kody TOTP oparte na HMAC-SHA1, można bez obaw zachować. W nowych projektach używaj HMAC-SHA256.

Dlaczego mój HMAC nie zgadza się z podpisem webhooka?

Najczęstsze przyczyny to obliczanie HMAC ze sparsowanego i ponownie zserializowanego JSON zamiast z surowej treści, końcowy znak nowego wiersza w wiadomości, niewłaściwy klucz lub format klucza (klucz w Base64 lub hex wpisany jako „Tekst” albo odwrotnie) oraz niewłaściwy algorytm. Hex czy Base64 nie ma tu znaczenia: pole „Porównaj z” akceptuje hex pisany małymi lub wielkimi literami, standardowy Base64 i Base64 bezpieczny dla URL.

Czym HMAC różni się od zwykłego hasha?
Zwykły hash, taki jak SHA-256, może obliczyć każdy, więc pokazuje on jedynie, że dane nie zmieniły się przypadkowo. HMAC można obliczyć tylko z kluczem tajnym, więc prawidłowy HMAC dowodzi także, że utworzył go ktoś, kto ma ten klucz.
Czy HMAC to to samo co podpis cyfrowy?

Nie. Obie strony HMAC współdzielą jeden sekret, więc każdy, kto może zweryfikować kod, może go też utworzyć. Podpisy takie jak RSA czy ECDSA (RS256 lub ES256 w tokenach JWT) tworzy się kluczem prywatnym, a sprawdza kluczem publicznym, więc osoby, które je weryfikują, nie mogą ich sfałszować.

Czy klucz tajny jest wysyłany na serwer?

Nie. HMAC-SHA1 i warianty SHA-2 są obliczane przez interfejs Web Crypto API przeglądarki, a HMAC-MD5 przez JavaScript na stronie. Klucz i wiadomość nigdy nie opuszczają urządzenia. Mimo to z kluczami produkcyjnymi obchodź się ostrożnie i wymień klucz, jeśli mógł zostać ujawniony.