Keine Werbung mögen? Gehen Werbefrei Heute

HMAC — Wie Webhooks wissen, dass Sie nicht lügen

Veröffentlicht am

Jeder Server kann eine POST-Anfrage an Ihren Webhook-Endpunkt senden. HMAC-Unterschriften sind die Methode, mit der legitime Absender die Payload bestätigen und Sie diese überprüfen können.

HMAC — Wie Webhooks wissen, dass Sie nicht lügen 1
ANZEIGE Entfernen?

Jedes Mal, wenn Stripe eine Karte belastet, sendet es eine Webhook-Nachricht. Jedes Mal, wenn GitHub einen Pull-Request zusammenführt, sendet es eine Webhook-Nachricht. Diese Plattformen senden POST-Anfragen an eine URL, die Sie ihnen gegeben haben — aber hier ist die unangenehme Wahrheit: Jeder andere kann eine POST-Anfrage an dieselbe URL senden.

Wie kann Ihr Server sicherstellen, dass die Anfrage tatsächlich von Stripe stammt und nicht von einem Angreifer, der Ihre Endpunkts-URL erraten hat? Die Antwort ist HMAC — und sobald Sie es verstehen, sehen Sie, warum es die Standardmethode in jeder ernsthaften API-Plattform ist.

Das Problem: Jeder kann eine POST-Anfrage an Ihren Endpunkt senden

Webhook-Endpunkte sind einfach URLs. Sie sind öffentlich erreichbar (sie müssen es sein, damit der Absender sie erreichen kann), und sie akzeptieren POST-Anfragen. Es gibt nichts, was einem böswilligen Nutzer verhindert, ein gefälschtes Payload zu erstellen und an Ihren Endpunkt zu senden.

Stellen Sie sich vor, dass Ihr Webhook-Handler dies tut, wenn er einen Ereignis empfängt:

if event["type"] == "payment.completed":
    fulfill_order(event["data"]["order_id"])

Ein Angreifer, der Ihre Endpunkts-URL kennt, könnte eine falsche payment.completed Ereignis mit einer beliebigen Bestell-ID senden. Ohne Verifikation würde Ihr Server bestellte Bestellungen vollständig erfüllen, die nie bezahlt wurden.

Sie benötigen eine Methode, um sicherzustellen, dass das Payload von jemandem stammt, der ein Geheimnis teilt, das Sie beide kennen — ohne das Geheimnis in der Anfrage zu übertragen.

Was ist HMAC?

HMAC steht für Hash-basierte Nachrichtenauthentifizierungscode. Es ist eine Konstruktion, die eine kryptographische Hash-Funktion (normalerweise SHA-256) mit einem Geheimnis kombiniert, um eine Signatur zu erzeugen. Die Signatur beweist zwei Dinge:

  • Authentizität — das Nachricht wurde von jemandem erstellt, der das Geheimnis besitzt
  • Integrität — das Nachricht wurde während der Übertragung nicht geändert

Die zentrale Eigenschaft von HMAC: Ohne das Geheimnis können Sie keine gültige Signatur erzeugen. Und Sie können die Signatur nicht rückgängig machen, um das Geheimnis zu ermitteln. Es ist ein einseitiger Beweis.

HMAC im Vergleich zu einem einfachen Hash

Ein einfacher Hash (wie SHA-256) der Payload löst das Integritätsproblem, aber nicht die Authentizität. Ein Angreifer, der eine gültige Payload abfängt, kann den Hash einer geänderten Payload neu berechnen. HMAC mischt Ihr Geheimnis in alle Schritte des Hash-Prozesses ein, sodass ohne das Geheimnis keine übereinstimmende Signatur erzeugt werden kann, selbst wenn man genau den verwendeten Hash-Algorithmus kennt.

Wie HMAC-Webhooks funktionieren

Der Prozess besteht aus drei Schritten: Schlüsselaustausch, Signierung und Verifikation.

Schritt 1: Schlüsselaustausch (happens once)

Wenn Sie einen Webhook mit einer Plattform wie Stripe oder GitHub konfigurieren, erzeugen sie einen Webhook-Secret und zeigen es Ihnen einmal. Sie speichern es auf dem Serverseite (nie in Client-Code oder öffentlichen Repos). Das ist alles — das Geheimnis wird nie über das Netzwerk weitergeleitet.

Schritt 2: Der Absender signiert das Payload

Bevor der Webhook gesendet wird, berechnet die Plattform einen HMAC-Signatur über den rohen Anfragenkörper mit Ihrem gemeinsamen Geheimnis:

signature = HMAC-SHA256(secret_key, request_body)

Die Signatur wird dann an die Anfrage angehängt, normalerweise in einem Header wie X-Hub-Signature-256 (GitHub) oder Stripe-Signature (Stripe). Der rohe Payload reist im Körper unverändert.

Schritt 3: Sie verifizieren beim Empfang

Wenn Ihr Server den Webhook empfängt, berechnen Sie erneut den gleichen HMAC mit dem rohen Körper und Ihrem gespeicherten Geheimnis, und vergleichen Sie das Ergebnis mit der Signatur im Header. Wenn sie übereinstimmen, ist das Payload authentisch und unverändert. Wenn nicht, lehnen Sie es ab.

expected = HMAC-SHA256(your_secret, raw_body)
if not constant_time_equal(expected, header_signature):
    return 401

Beachten konstante Zeitvergleich — wir kommen später darauf zurück, warum das wichtig ist.

Realwelt-Beispiele

Stripe

Stripe sendet einen Stripe-Signature Header, der eine Zeitstempel und eine oder mehrere Signatur enthält:

Stripe-Signature: t=1679000000,v1=abc123...,v0=oldformat...

Die Signatur wird über timestamp.payload (angehängt mit einem Punkt) berechnet. Die Einbeziehung des Zeitstempels ermöglicht Stripe, sich gegen Replay-Angriffe zu verteidigen — wenn ein Angreifer einen gültigen signierten Antrag abfängt und später erneut sendet, können Sie ihn abweisen, weil der Zeitstempel zu alt ist.

GitHub

GitHub sendet einen X-Hub-Signature-256 Header im Format sha256=<hex_digest>. Die Signatur ist der HMAC-SHA256 des rohen Körpers mit dem Webhook-Secret, das Sie in Ihren Repository-Einstellungen konfiguriert haben.

Shopify

Shopify verwendet einen X-Shopify-Hmac-Sha256 Header mit einer Base64-gecodierten HMAC-SHA256-Signatur — gleiches Konzept, andere Codierung.

Verifikation im Code

Hier ist, wie die Verifikation in drei gängigen Sprachen aussieht. Der Muster ist identisch — nur die Bibliotheken unterscheiden sich.

Python

import hmac
import hashlib

def verify_webhook(secret: str, payload: bytes, signature_header: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    
    received = signature_header.removeprefix("sha256=")
    return hmac.compare_digest(expected, received)

Node.js

const crypto = require('crypto');

function verifyWebhook(secret, rawBody, signatureHeader) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  
  const received = signatureHeader.replace('sha256=', '');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(received)
  );
}

PHP

function verifyWebhook(string $secret, string $rawBody, string $signatureHeader): bool {
    $expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
    return hash_equals($expected, $signatureHeader);
}

Fehler, die die Sicherheit brechen

1. Verwendung von == anstatt konstanter Zeitvergleich

Standardstring-Gleichheit (==, ===) kürzt sich sofort, sobald ein Unterschied gefunden wird. Dies erzeugt einen Zeitseitenkanal: Ein Angreifer kann messen, wie lange Ihr Server unterschiedliche Signatur abweist. Strings, die eine längere Präfix teilen, dauern etwas länger, um abgelehnt zu werden. Mit genügend Anfragen kann ein Angreifer dies nutzen, um ein gültiges Signature Byte für Byte zu rekonstruieren.

Verwenden Sie immer einen konstanten Zeitvergleich: hmac.compare_digest() in Python, crypto.timingSafeEqual() in Node.js, hash_equals() in PHP.

2. Parsen des Körpers vor der Verifikation

HMAC wird über die rohen Bytes des Anfragenkörpers berechnet. Wenn Sie zuerst die JSON parsen und dann erneut serialisieren, können Sie eine andere Bytefolge erhalten (verschiedene Schlüsselreihenfolge, Leerzeichen, Kodierung). Fangen Sie immer den rohen Körper vor dem Zugriff durch die Frameworks’ Body-Parser auf, und verifizieren Sie dann gegen diesen.

3. Keine Überprüfung von Replay-Angriffen

Ein gültig signierter Antrag ist gültig für immer — es sei denn, Sie prüfen den Zeitstempel. Wenn eine Plattform einen Zeitstempel in ihre Signaturmethode einbezieht (Stripe tut das; GitHub nicht), lehnen Sie Anfragen ab, bei denen der Zeitstempel älter als einige Minuten ist. Dies verhindert, dass ein Angreifer einen legitimen Antrag abfängt und erneut sendet.

4. Das Geheimnis direkt in der Quellcode zu hardcodieren

Webhook-Geheimnisse sollten in Umgebungsvariablen oder einem Secrets-Manager leben, nie in Versionskontrolle eingebunden. Ein ausgelieferter Geheimnis bedeutet, dass ein Angreifer jedes Payload für immer fälschen kann — bis Sie es rotieren.

Was HMAC nicht schützt

HMAC beweist, dass das Payload von jemandem mit dem Geheimnis signiert wurde. Es schützt jedoch nicht vor: nicht Ein kompromittierter Absender

  • — wenn die Signaturinfrastruktur von Stripe kompromittiert wäre, hätten falsche Ereignisse immer noch gültige Signatur Replay-Angriffe
  • — es sei denn, Sie überprüfen auch einen Zeitstempel oder einen Nonce Geheimhaltung
  • — HMAC verschlüsselt nichts; der Payload reist im Klartext (obwohl HTTPS dies behandelt) Für die meisten Webhook-Integrationen reicht HMAC über HTTPS aus.

HMAC — Wie Webhooks wissen, dass Sie nicht lügen 2

Möchten Sie werbefrei genießen? Werde noch heute werbefrei

Erweiterungen installieren

IO-Tools zu Ihrem Lieblingsbrowser hinzufügen für sofortigen Zugriff und schnellere Suche

Zu Chrome-Erweiterung Zu Kantenerweiterung Zu Firefox-Erweiterung Zu Opera-Erweiterung

Die Anzeigetafel ist eingetroffen!

Anzeigetafel ist eine unterhaltsame Möglichkeit, Ihre Spiele zu verfolgen. Alle Daten werden in Ihrem Browser gespeichert. Weitere Funktionen folgen in Kürze!

ANZEIGE Entfernen?
ANZEIGE Entfernen?
ANZEIGE Entfernen?

Nachrichtenecke mit technischen Highlights

Beteiligen Sie sich

Helfen Sie uns, weiterhin wertvolle kostenlose Tools bereitzustellen

Kauf mir einen Kaffee
ANZEIGE Entfernen?