Zo gebruik je het
- Kies het algoritme. HMAC-SHA256 is standaard geselecteerd en wordt door de meeste webhooks en API's gebruikt.
- Voer de geheime sleutel in en zet Sleutelformaat op Tekst (gelezen als UTF-8), Hex of Base64. Kies Hex of Base64 als de sleutel uit ruwe bytes bestaat en niet uit een string die op een wachtwoord lijkt.
- Typ of plak het bericht, zet de invoer op Hex voor ruwe bytes, of klik op Bestand openen. De HMAC wordt bijgewerkt terwijl je typt.
- Kies bij Uitvoer als hex (kleine letters), HEX (hoofdletters) of Base64 en kopieer het resultaat, of plak een ontvangen handtekening in het veld Vergelijken met; je ziet dan Komt overeen of Komt niet overeen.
Zo werkt HMAC
HMAC (hash-based message authentication code, RFC 2104) combineert een cryptografische hash met een geheime sleutel. Alleen wie de sleutel kent, kan de juiste waarde voor een bericht berekenen. Een overeenkomende HMAC bewijst dus twee dingen tegelijk: het bericht is niet gewijzigd, en het komt van iemand die de sleutel heeft.
De constructie is H((K ⊕ opad) ‖ H((K ⊕ ipad) ‖ message)). De sleutel wordt eerst gehasht als hij langer is dan de blokgrootte van de hash (64 bytes voor MD5, SHA-1 en SHA-256, 128 voor SHA-384 en SHA-512), dan met nullen aangevuld tot die grootte, en vervolgens met XOR gecombineerd met ipad (bytes 0x36) voor een binnenste hash over het bericht en met opad (bytes 0x5c) voor een buitenste hash over het binnenste resultaat. Een naïeve constructie als SHA-256(key ‖ message) heeft geen buitenste hash. Wie één tag ziet, kan dan gegevens aan het bericht toevoegen en zonder de sleutel een geldige nieuwe tag berekenen (een length-extension-aanval).
De uitvoer heeft de lengte van de onderliggende hash: 32 bytes, of 64 hextekens, voor HMAC-SHA256. RFC 2104 raadt een sleutel aan die minstens zo lang is, en de generator voor willekeurige Base64 maakt geschikte sleutels.
Waar HMAC-handtekeningen worden gebruikt
- GitHub-webhooks. De header
X-Hub-Signature-256bestaat uitsha256=, gevolgd door de HMAC-SHA256 in hex van de ruwe body van het verzoek, met het webhookgeheim als sleutel. Je kunt de volledige headerwaarde in het veld Vergelijken met plakken; het voorvoegselsha256=wordt genegeerd. - Stripe-webhooks. De header
Stripe-Signaturebevat een tijdstempelten een handtekeningv1: de HMAC-SHA256 in hex van de tijdstempel, een punt en de ruwe body, met als sleutel het endpointgeheim (whsec_...), ingevoerd als tekst. - Shopify-webhooks.
X-Shopify-Hmac-Sha256bevat de HMAC-SHA256 van de ruwe body in Base64, met het client secret van de app als sleutel. Kies dus Base64 als uitvoer of plak de headerwaarde in het veld Vergelijken met. - AWS Signature Version 4. De ondertekeningssleutel wordt afgeleid door HMAC-SHA256 aan elkaar te schakelen: eerst de datum, met als sleutel
AWS4plus de secret access key, en daarna de regio, de service enaws4_request, telkens met het vorige resultaat als sleutel. Zet Sleutelformaat op Hex om de uitvoer van de ene stap in de volgende te gebruiken. - JSON Web Tokens. HS256, HS384 en HS512 zijn HMAC-SHA256, -384 en -512 over de gecodeerde header, een punt en de gecodeerde payload. Het derde deel van het token is die HMAC in URL-veilige Base64, en het veld Vergelijken met accepteert die ongewijzigd. De JWT-decoder verifieert volledige tokens.
Bereken de HMAC altijd over de ruwe body, precies zoals die is ontvangen. JSON parsen en opnieuw serialiseren verandert de spaties of de volgorde van de sleutels, en zelfs één extra regeleinde geeft een totaal andere HMAC.
HMAC berekenen in code
# Python
import hmac, hashlib
sig = hmac.new(b'key', b'message', hashlib.sha256).hexdigest()
hmac.compare_digest(sig, received) # vergelijking in constante tijd
// Node.js
const crypto = require('crypto');
const sig = crypto.createHmac('sha256', 'key').update('message').digest('hex');
// timingSafeEqual geeft een fout als de lengtes verschillen, controleer die dus eerst
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(received));
// PHP: het bericht komt vóór de sleutel
$sig = hash_hmac('sha256', 'message', 'key');
hash_equals($sig, $received);
# OpenSSL: een sleutel als tekst, daarna dezelfde sleutel als hex
printf '%s' 'message' | openssl dgst -sha256 -hmac 'key'
printf '%s' 'message' | openssl dgst -sha256 -mac HMAC -macopt hexkey:6b6579
# Testvector: sleutel "key", bericht "The quick brown fox jumps over the lazy dog"
# HMAC-SHA256 = f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
Gebruik een vergelijking in constante tijd zoals hierboven als je in je eigen code een handtekening verifieert. Een gewone == stopt bij het eerste teken dat verschilt, en met dat tijdsverschil kan een aanvaller byte voor byte een geldige handtekening vinden. Weiger bij schema's met een tijdstempel, zoals dat van Stripe, ook verzoeken waarvan de tijdstempel meer dan een paar minuten oud is; zo blokkeer je replay-aanvallen.
Veelgestelde vragen
Is HMAC-MD5 of HMAC-SHA1 nog veilig?
Collisieaanvallen breken MD5 en SHA-1 als gewone hashes, maar ze bieden geen praktische manier om een HMAC te vervalsen, want die hangt af van andere eigenschappen van de hash en van een geheime sleutel (RFC 6151 bespreekt HMAC-MD5). Integraties die ze vereisen, zoals TOTP-codes op basis van HMAC-SHA1, kun je gerust blijven gebruiken. Kies voor nieuwe ontwerpen HMAC-SHA256.
Waarom komt mijn HMAC niet overeen met de handtekening van de webhook?
De gebruikelijke oorzaken zijn: geparste en opnieuw geserialiseerde JSON hashen in plaats van de ruwe body, een regeleinde aan het eind van het bericht, het verkeerde geheim of sleutelformaat (een Base64- of hexgeheim ingevoerd als Tekst, of andersom) en het verkeerde algoritme. Hex of Base64 maakt hier niet uit: het veld Vergelijken met accepteert hex in kleine letters en hoofdletters, standaard Base64 en URL-veilige Base64.
Wat is het verschil tussen HMAC en een gewone hash?
Is een HMAC hetzelfde als een digitale handtekening?
Nee. Bij een HMAC delen beide kanten één geheim, dus iedereen die een tag kan verifiëren, kan er ook een maken. Handtekeningen zoals RSA of ECDSA (RS256 of ES256 in JWT's) worden gemaakt met een privésleutel en gecontroleerd met een publieke sleutel, zodat wie ze verifieert ze niet kan vervalsen.
Wordt mijn geheime sleutel naar een server gestuurd?
Nee. HMAC-SHA1 en de SHA-2-varianten worden berekend met de Web Crypto API van je browser, en HMAC-MD5 met JavaScript op de pagina. De sleutel en het bericht verlaten je apparaat nooit. Ga toch zorgvuldig om met productiegeheimen en vervang een sleutel als die mogelijk is uitgelekt.