Diese Anleitung erklärt, was ein HMAC ist und wie Sie als Empfänger eines Webhooks die Signatur sicher prüfen.

Was ist HMAC?

HMAC steht für Hash-based Message Authentication Code. Es ist ein Mechanismus, der die Authentizität und Integrität von Nachrichten sicherstellt.

So funktioniert das Prinzip:

  1. Der Sender erzeugt aus dem Nachrichteninhalt (Payload) und einem gemeinsam vereinbarten geheimen Schlüssel (Secret) mithilfe eines Hash-Algorithmus (z. B. SHA-256) eine Signatur.
  2. Der Empfänger berechnet mit demselben Schlüssel und Algorithmus eine eigene Signatur und vergleicht sie mit der empfangenen.
  3. Stimmen beide Signaturen überein, ist die Nachricht authentisch und wurde nicht verändert.

💡 Tipp: HMAC schützt nicht nur vor gefälschten Nachrichten, sondern auch vor nachträglicher Manipulation – selbst wenn ein Angreifer die Übertragung mitlesen kann.


Webhook mit HMAC validieren

Schritt 1: Webhook empfangen

Wenn venabo einen Webhook sendet, erhalten Sie zwei Bestandteile:

Bestandteil Beschreibung Beispielwert
Body (Payload) Die eigentlichen Nutzdaten als JSON {„event“:“timeEntry.created“,…}
HTTP-Header: HMAC-Signature Die berechnete Signatur des Payloads a3f8c2…
HTTP-Header: HMAC-Algorithm Der verwendete Hash-Algorithmus sha256

Schritt 2: HMAC selbst berechnen

Für die eigene Berechnung benötigen Sie diese drei Elemente:

  1. Payload – den Body der empfangenen Anfrage, exakt wie erhalten
  2. Algorithmus – aus dem Header HMAC-Algorithm (Standard: sha256)
  3. Geheimer Schlüssel – das vorab mit venabo vereinbarte Secret

⚠️ Hinweis: Verwenden Sie den Payload unverändert, so wie er empfangen wurde. Jede Formatierung, zusätzliches Leerzeichen oder Zeichenkodierungsänderung führt zu einer abweichenden Signatur.

Schritt 3: Signaturen vergleichen

Vergleichen Sie die selbst berechnete Signatur mit der empfangenen aus dem HTTP-Header. Stimmen beide überein, ist der Webhook authentisch. Weichen sie ab, lehnen Sie die Anfrage ab.

💡 Tipp: Nutzen Sie immer einen zeitkonstanten Vergleich (z. B. hash_equals() in PHP) statt einfachem ==. So verhindern Sie Timing-Angriffe.


PHP-Beispiel: Webhook validieren

Das folgende Beispiel zeigt eine vollständige Validierung in PHP:


Praxisbeispiel

Szenario: venabo meldet eine neu erfasste Zeitbuchung an Ihr System. Sie möchten sicherstellen, dass die Anfrage tatsächlich von venabo stammt und nicht manipuliert wurde.

Element Wert (Beispiel)
Payload (Body) {„event“:“timeEntry.created“,“duration“:3600}
Geheimer Schlüssel mein_geheimes_secret
Algorithmus sha256
Berechnete Signatur hash_hmac(’sha256′, $payload, ‚mein_geheimes_secret‘)
Ergebnis Signatur stimmt überein → HTTP 200, Verarbeitung gestartet

Sicherheitshinweise

⚠️ Hinweis: Speichern Sie den geheimen Schlüssel niemals im Quellcode oder in öffentlichen Repositories. Verwenden Sie Umgebungsvariablen oder einen sicheren Secrets-Manager.

⚖️ Hinweis: Teilen Sie den geheimen Schlüssel ausschließlich über sichere Kanäle und nur mit autorisierten Personen. Ein kompromittierter Schlüssel ermöglicht das Fälschen beliebiger Webhook-Nachrichten.


Häufige Fragen

Was passiert, wenn die Signaturen nicht übereinstimmen?

Lehnen Sie die Anfrage mit dem HTTP-Statuscode 401 (Unauthorized) ab und verarbeiten Sie den Payload nicht weiter. Eine abweichende Signatur bedeutet, dass die Nachricht entweder nicht von venabo stammt oder auf dem Übertragungsweg verändert wurde.

Warum darf ich den Payload vor der Validierung nicht verändern?

venabo berechnet die Signatur auf Basis des exakten Payloads, den es sendet. Schon ein einzelnes zusätzliches Leerzeichen, eine geänderte Zeichenkodierung oder eine andere Reihenfolge der JSON-Schlüssel erzeugt eine vollständig andere Signatur. Lesen Sie den Body daher immer als rohen Byte-String, bevor Sie ihn parsen.

Kann ich einen anderen Hash-Algorithmus als SHA-256 verwenden?

venabo sendet den verwendeten Algorithmus im Header HMAC-Algorithm mit. Lesen Sie diesen Wert aus und verwenden Sie ihn für Ihre Berechnung. Aktuell setzt venabo standardmäßig sha256 ein. Stimmen Sie Algorithmusänderungen vorab mit venabo ab.

Warum soll ich hash_equals() statt == verwenden?

Ein einfacher Zeichenkettenvergleich mit == bricht ab, sobald das erste Zeichen abweicht. Dadurch kann ein Angreifer über die Antwortzeit Rückschlüsse auf die korrekte Signatur ziehen (Timing-Angriff). hash_equals() benötigt unabhängig vom Ergebnis immer gleich lang und verhindert diesen Angriff zuverlässig.


Auf einen Blick

Schritt Aktion Wichtig
1 Payload und Header auslesen Body unverändert als Rohtext einlesen
2 Eigene Signatur berechnen Algorithmus aus Header verwenden, Secret sicher speichern
3 Signaturen vergleichen hash_equals() statt == nutzen
4 Ergebnis verarbeiten HTTP 200 bei Erfolg, HTTP 401 bei Abweichung