HMAC Python — hmac.new() SHA-256 Anleitung mit Beispielen

·DevOps Engineer & Python Automation Specialist·Geprüft vonMaria Santos·Veröffentlicht

Nutze das kostenlose HMAC Generator direkt im Browser – keine Installation erforderlich.

HMAC Generator online testen →

Jeder Webhook-Callback, jede signierte API-Anfrage, jede Stripe- oder GitHub-Ereignisbenachrichtigung verwendet eine HMAC-Signatur, um zu beweisen, dass die Payload nicht manipuliert wurde. Pythons hmac Modul verarbeitet HMAC-SHA256 in Python mit einem einzigen Funktionsaufruf: hmac.new(key, msg, hashlib.sha256). Kein pip install, keine C-Erweiterung, keine Drittanbieter-Abhängigkeit. Für schnelle einmalige Signaturprüfungen ohne Code zu schreiben, liefert der Online-HMAC-Generator das Ergebnis sofort. Diese Anleitung behandelt hmac.new(), hmac.digest(), hmac.compare_digest(), Base64-Kodierung, Webhook-Verifizierung, API-Request-Signierung und alle Hash-Algorithmen von SHA-1 bis SHA-512. Alle Beispiele richten sich an Python 3.7+.

  • hmac.new(key, msg, hashlib.sha256) ist der Standard-Einstiegspunkt — key und msg müssen bytes sein, digestmod ist seit Python 3.4 verpflichtend.
  • hmac.digest(key, msg, "sha256") ist eine schnellere einmalige Alternative, die in Python 3.7 eingeführt wurde — gibt rohe Bytes zurück, kein Zwischenobjekt.
  • Signaturen immer mit hmac.compare_digest() verifizieren, um Timing-Angriffe zu verhindern — niemals == für HMAC-Vergleiche verwenden.
  • Rohe .digest()-Ausgabe für HTTP-Header und Webhook-Signaturen Base64-kodieren: base64.b64encode(h.digest()).
  • Das hmac-Modul akzeptiert jeden hashlib-Algorithmus: sha1, sha256, sha384, sha512, md5, blake2b.

Was ist HMAC?

HMAC (Hash-based Message Authentication Code) ist eine in RFC 2104 definierte Konstruktion, die einen geheimen Schlüssel mit einer Hash-Funktion kombiniert, um ein Authentifizierungstag fester Größe zu erzeugen. Im Gegensatz zu einem einfachen Hash (den jeder berechnen kann) erfordert ein HMAC die Kenntnis des geheimen Schlüssels. Damit lässt sich sowohl die Integrität als auch die Authentizität einer Nachricht prüfen. Ändert sich auch nur ein einziges Byte der Nachricht oder des Schlüssels, ist die Ausgabe vollständig anders. Die Konstruktion funktioniert, indem der Schlüssel XOR-verknüpft mit zwei verschiedenen Padding-Konstanten (ipad und opad) gehasht wird und die Nachricht zwischen zwei Hash-Operationen eingebettet wird. Pythons hmac Modul implementiert diesen RFC direkt.

Before · Python
After · Python
# Einfacher SHA-256-Hash — kein geheimer Schlüssel, jeder kann ihn berechnen
hashlib.sha256(b"payment:9950:USD").hexdigest()
# "7a3b1c..."  (deterministisch, öffentlich)
# HMAC-SHA256 — erfordert den geheimen Schlüssel zur Erzeugung
hmac.new(b"api_secret", b"payment:9950:USD", hashlib.sha256).hexdigest()
# "e4f2a8..."  (nur der Schlüsselinhaber kann es berechnen)

hmac.new() — Der Standard-Einstiegspunkt

Das hmac Modul ist Teil der Python-Standardbibliothek. Zwei Imports und du bist startklar: import hmac, hashlib. Die drei wichtigsten Funktionen sind hmac.new() (erstellt ein HMAC-Objekt), hmac.digest() (einmalig, Python 3.7+) und hmac.compare_digest() (zeitkonstanter Vergleich). Kein pip install erforderlich.

hmac.new(key, msg, digestmod) nimmt drei Argumente. Sowohl key als auch msg müssen bytes-artige Objekte sein ( bytes, bytearray oder memoryview). Das digestmod Argument ist seit Python 3.4 verpflichtend und akzeptiert jeden hashlib Konstruktor (wie hashlib.sha256) oder einen String-Namen wie "sha256".

Python 3.7+ — minimales HMAC-SHA256-Beispiel
import hmac
import hashlib

key = b"webhook_signing_key_2026"
message = b'{"event":"invoice.paid","invoice_id":"inv_8f3a","amount":19900}'

# HMAC-Objekt erstellen und die Hex-Signatur abrufen
signature = hmac.new(key, message, hashlib.sha256).hexdigest()
print(signature)
# "b4e74f6c9a1d3e5f8b2a7c0d4e6f1a3b5c7d9e0f2a4b6c8d0e1f3a5b7c9d0e2f"

Das HMAC-Objekt bietet zwei Ausgabemethoden. .digest() gibt rohe Bytes zurück (32 Bytes für SHA-256, 64 für SHA-512). .hexdigest() gibt einen Kleinbuchstaben-Hex-String zurück. Der Hex-String ist ein gewöhnlicher Python str — kein Dekodierungsschritt erforderlich.

Python 3.7+ — .digest() vs .hexdigest()
import hmac
import hashlib

key = b"service_auth_key"
msg = b"GET /api/v2/orders 2026-03-28T14:30:00Z"

h = hmac.new(key, msg, hashlib.sha256)

raw_bytes = h.digest()
print(type(raw_bytes), len(raw_bytes))
# <class 'bytes'> 32

hex_string = h.hexdigest()
print(type(hex_string), len(hex_string))
# <class 'str'> 64

# Sie repräsentieren dieselben Daten — Hex ist nur eine String-Kodierung der Bytes
assert raw_bytes.hex() == hex_string

Wenn dein Schlüssel oder deine Nachricht ein Python-String ist, rufe .encode() auf, um ihn in Bytes umzuwandeln, bevor du ihn an hmac.new() übergibst. Das stolpert fast jeden beim ersten Mal — Python 3 Strings sind Unicode, keine Bytes, und das hmac-Modul lehnt sie ab.

Python 3.7+ — Strings in Bytes konvertieren
import hmac
import hashlib

# String-Schlüssel und Nachricht — .encode() konvertiert zu UTF-8-Bytes
api_key = "sk_live_9f3a2b7c4d8e"
request_body = '{"customer_id":"cust_4421","plan":"enterprise"}'

signature = hmac.new(
    api_key.encode(),
    request_body.encode(),
    hashlib.sha256
).hexdigest()

print(signature)
# "3a9f1b..."  — konsistente Hex-String-Ausgabe
Hinweis:Der digestmod Parameter hat seit Python 3.4 keinen Standardwert mehr. Der Aufruf von hmac.new(key, msg) ohne ihn wirft TypeError. Vor 3.4 war MD5 der Standard, weshalb die Python-Maintainer den Standard entfernt haben — um eine explizite, sichere Wahl zu erzwingen.

HMAC-SHA256 Base64, SHA-1, SHA-512 und MD5

Die hmac.new() Funktion arbeitet mit jedem Hash-Algorithmus, der in hashlib verfügbar ist. Die meisten Webhook-Anbieter und API-Gateways verwenden HMAC-SHA256, aber du wirst SHA-1 in OAuth 1.0a, SHA-512 in Protokollen, die es vorschreiben, und MD5 in Legacy-Systemen begegnen, die noch nicht aktualisiert wurden.

HMAC-SHA256 mit Base64-Ausgabe

Viele Webhook-Anbieter senden die Signatur als Base64-kodierten String in einem HTTP-Header. Um das gleiche Format zu erzeugen, übergib die rohen .digest() Bytes an base64.b64encode().

Python 3.7+ — HMAC-SHA256 Base64-Kodierung
import hmac
import hashlib
import base64

key = b"whsec_MbkP7x9yFqHGn3tRdWz5"
payload = b'{"id":"evt_1Nq","type":"charge.succeeded","data":{"amount":4200}}'

# Roher Digest → Base64 (üblich für Authorization-Header und Webhook-Signaturen)
raw_digest = hmac.new(key, payload, hashlib.sha256).digest()
b64_signature = base64.b64encode(raw_digest).decode("ascii")

print(b64_signature)
# "dGhpcyBpcyBhIHNhbXBsZSBzaWduYXR1cmU="

# Dieser Wert wird mit dem X-Signature-Header verglichen
header_value = f"sha256={b64_signature}"
print(header_value)
# "sha256=dGhpcyBpcyBhIHNhbXBsZSBzaWduYXR1cmU="

HMAC-SHA1 — Legacy-Protokoll-Kompatibilität

SHA-1 gilt für neue Entwürfe als schwach, aber HMAC-SHA1 wird von OAuth 1.0a und einigen älteren Webhook-Implementierungen noch vorgeschrieben. Der Code ist identisch — tausche einfach den Algorithmus aus.

Python 3.7+ — HMAC-SHA1
import hmac
import hashlib

consumer_secret = b"oauth_consumer_secret_2026"
token_secret = b"oauth_token_secret_2026"

# OAuth 1.0a verwendet consumer_secret&token_secret als Signierschlüssel
signing_key = consumer_secret + b"&" + token_secret
base_string = b"GET&https%3A%2F%2Fapi.service.com%2Fv1%2Forders&oauth_nonce%3D7f3a91bc"

sig = hmac.new(signing_key, base_string, hashlib.sha1).digest()

import base64
oauth_signature = base64.b64encode(sig).decode("ascii")
print(oauth_signature)
# "Tza3R9sE..."  — URL-kodiere dies für den Authorization-Header

HMAC-SHA512 — Längere Ausgabe

Python 3.7+ — HMAC-SHA512
import hmac
import hashlib

key = b"high_security_signing_key_64_bytes_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
msg = b'{"transfer_id":"xfr_9c2e","amount":500000,"currency":"EUR"}'

h = hmac.new(key, msg, hashlib.sha512)

print(len(h.digest()))   # 64 Bytes (512 Bits)
print(len(h.hexdigest()))  # 128 Hex-Zeichen
print(h.hexdigest()[:40] + "...")
# "8e3a1f9b2c4d6e7f0a1b3c5d7e9f0a2b4c6d8e0f..."

HMAC-MD5 — Nur für Legacy

Python 3.7+ — HMAC-MD5
import hmac
import hashlib

# MD5 ist kryptografisch gebrochen — nur für Legacy-Protokoll-Kompatibilität verwenden
key = b"legacy_api_key"
msg = b"action=charge&amount=1500&merchant=store_42"

sig = hmac.new(key, msg, hashlib.md5).hexdigest()
print(sig)  # 32-stelliger Hex-String
# "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Warnung:HMAC-MD5 ist nur für die Abwärtskompatibilität mit Systemen akzeptabel, die nicht migriert werden können. Für jedes neue Projekt mindestens HMAC-SHA256 verwenden. MD5 hat bekannte Kollisionsschwachstellen, die zwar im HMAC-Modus weniger direkt ausnutzbar sind, es aber dennoch zu einer schlechten Standardwahl machen.

hmac.new() Parameter-Referenz

Die Konstruktorsignatur lautet hmac.new(key, msg=None, digestmod). Alle drei Funktionen im Modul folgen dem gleichen Muster für Schlüssel- und Algorithmus-Argumente.

hmac.new() Konstruktor

Parameter
Typ
Standard
Beschreibung
key
bytes | bytearray
(erforderlich)
Der geheime Schlüssel — muss bytes sein, kein String
msg
bytes | None
None
Erste Nachricht zum Hashen; weitere Daten können per .update() hinzugefügt werden
digestmod
str | callable
(erforderlich)
Hash-Algorithmus — z. B. hashlib.sha256 oder der String "sha256"

hmac.digest() einmalig (Python 3.7+)

Parameter
Typ
Beschreibung
key
bytes
Der geheime Schlüssel
msg
bytes
Die zu authentifizierende Nachricht
digest
str | callable
Hash-Algorithmus — entspricht digestmod in hmac.new()

Der digestmod Parameter akzeptiert entweder ein Callable (wie hashlib.sha256) oder einen String-Namen (wie "sha256"). Die Callable-Form wird bevorzugt, da sie zur Import-Zeit validiert wird — ein Tippfehler in der String-Form schlägt erst zur Laufzeit fehl.

hmac.digest() — Schnelles einmaliges HMAC (Python 3.7+)

Python 3.7 hat hmac.digest(key, msg, digest) als Funktion auf Modulebene hinzugefügt. Sie berechnet den HMAC in einem einzigen Aufruf ohne ein Zwischen-HMAC-Objekt zu erzeugen. Der Rückgabewert sind rohe Bytes (äquivalent zum Aufruf von .digest() auf dem Objekt). Diese Funktion verwendet eine optimierte C-Implementierung auf CPython und vermeidet den Objekt-Allokations-Overhead, was sie in engen Schleifen messbar schneller macht.

Python 3.7+ — hmac.digest() einmalig
import hmac
import hashlib

key = b"batch_signing_key_2026"
messages = [
    b'{"order_id":"ord_001","total":4500}',
    b'{"order_id":"ord_002","total":8900}',
    b'{"order_id":"ord_003","total":2200}',
]

# Einmaliger Digest — kein Zwischen-HMAC-Objekt
signatures = [hmac.digest(key, msg, hashlib.sha256) for msg in messages]

# In Hex für die Ausgabe konvertieren
for msg, sig in zip(messages, signatures):
    print(f"{msg[:30]}... -> {sig.hex()[:24]}...")

Die Einschränkung: hmac.digest() gibt nur rohe Bytes zurück. Wenn du den Hex-String direkt benötigst, brauchst du weiterhin hmac.new() für seine .hexdigest() Methode oder verkette .hex() auf das Bytes-Ergebnis.

Hinweis:hmac.digest() unterstützt keine inkrementellen .update() Aufrufe. Wenn du eine große Datei in Blöcken liest und deren Inhalt mit HMAC verarbeiten musst, bleib bei hmac.new() und rufe .update(chunk) in einer Schleife auf.

HMAC-Signatur von Webhooks und API-Antworten verifizieren

Die häufigste Verwendung von HMAC in Python ist die Verifizierung von Webhook-Signaturen. Jeder große Anbieter (Stripe, GitHub, Shopify, Twilio) signiert Payloads mit HMAC-SHA256 und sendet die Signatur in einem Header. Das Muster ist immer gleich: den HMAC über den rohen Request-Body neu berechnen, dann mit hmac.compare_digest() vergleichen.

Webhook-Signatur-Verifizierung

Python 3.7+ — Webhook-HMAC-Verifizierung (Flask)
import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = b"whsec_MbkP7x9yFqHGn3tRdWz5"

@app.route("/webhooks/payments", methods=["POST"])
def handle_payment_webhook():
    # Rohen Body abrufen — muss exakt dem signierten Inhalt entsprechen
    raw_body = request.get_data()

    # Signatur aus dem Header lesen
    received_sig = request.headers.get("X-Signature-256", "")

    # HMAC über den rohen Body neu berechnen
    expected_sig = hmac.new(WEBHOOK_SECRET, raw_body, hashlib.sha256).hexdigest()

    # Zeitkonstanter Vergleich — verhindert Timing-Angriffe
    if not hmac.compare_digest(f"sha256={expected_sig}", received_sig):
        abort(403, "Ungültige Signatur")

    # Signatur verifiziert — Ereignis verarbeiten
    event = request.get_json()
    print(f"Verifiziertes Ereignis: {event['type']} für {event['data']['amount']}")
    return "", 200

Die hmac.compare_digest() Funktion vergleicht zwei Strings oder Byte-Sequenzen in konstanter Zeit. Ein normaler == Vergleich schließt beim ersten nicht übereinstimmenden Byte kurz. Ein Angreifer kann die Antwortzeit über viele Anfragen messen und die erwartete Signatur Byte für Byte schrittweise rekonstruieren. Der zeitkonstante Vergleich eliminiert diesen Seitenkanal.

GitHub-Webhook-Verifizierung

GitHubs Webhook-Format veranschaulicht das vollständige Muster. Es sendet einen X-Hub-Signature-256 Header, der sha256= gefolgt vom Hex-kodierten HMAC-SHA256 des rohen Request-Bodys enthält, signiert mit dem Webhook-Geheimnis, das du in deinen Repository-Einstellungen konfigurierst. Der wesentliche Unterschied zur allgemeinen Webhook-Verifizierung ist, dass du das sha256= Präfix vor dem Vergleich entfernen musst und die rohen Bytes des Request-Bodys lesen musst — das vorherige Parsen des JSON ändert die Byte-Darstellung und bricht die Verifizierung.

Python 3.7+ — GitHub X-Hub-Signature-256-Verifizierung
import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)
GITHUB_WEBHOOK_SECRET = b"your_github_webhook_secret"

@app.route("/webhooks/github", methods=["POST"])
def handle_github_webhook():
    # GitHub sendet: X-Hub-Signature-256: sha256=<hex_digest>
    sig_header = request.headers.get("X-Hub-Signature-256", "")

    if not sig_header.startswith("sha256="):
        abort(403, "Fehlender oder fehlerhafter Signatur-Header")

    received_hex = sig_header[len("sha256="):]
    raw_body = request.get_data()  # rohe Bytes — JSON nicht vorher parsen

    expected_hex = hmac.new(
        GITHUB_WEBHOOK_SECRET, raw_body, hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(expected_hex, received_hex):
        abort(403, "Signatur stimmt nicht überein — Payload wurde möglicherweise manipuliert")

    event_type = request.headers.get("X-GitHub-Event", "unknown")
    payload = request.get_json()
    print(f"Verifiziertes GitHub {event_type}-Ereignis: {payload.get('action', '')}")
    return "", 200

Das gleiche Muster gilt für Shopify (X-Shopify-Hmac-SHA256) und Twilio (X-Twilio-Signature), mit dem einzigen Unterschied im Header-Namen und ob die Signatur Hex- oder Base64-kodiert ist. Prüfe immer die Anbieterdokumentation, um das Kodierungsformat zu bestätigen — das Verwechseln von Hex und Base64 ist die häufigste Ursache für Signatur-Fehlanpassungsfehler.

API-Request-Authentifizierung mit HMAC

Einige APIs verlangen, dass der Client jede Anfrage mit HMAC signiert. Der signierte String enthält normalerweise die HTTP-Methode, den Pfad, den Zeitstempel und den Request-Body. Hier ist ein Muster für die interne Dienst-zu-Dienst-Authentifizierung.

Python 3.7+ — API-Anfragen mit HMAC-SHA256 signieren
import hmac
import hashlib
import time
import json

def sign_request(secret: bytes, method: str, path: str, body: str) -> dict:
    """HMAC-SHA256-Signatur für eine API-Anfrage generieren."""
    timestamp = str(int(time.time()))

    # Signier-String aufbauen — Methode + Pfad + Zeitstempel + Body
    signing_string = f"{method}\n{path}\n{timestamp}\n{body}"

    signature = hmac.new(
        secret,
        signing_string.encode(),
        hashlib.sha256
    ).hexdigest()

    return {
        "X-Timestamp": timestamp,
        "X-Signature": signature,
    }

# Verwendung
api_secret = b"sk_hmac_9f3a2b7c4d8e1a6f"
body = json.dumps({"customer_id": "cust_4421", "action": "suspend_account"})

headers = sign_request(api_secret, "POST", "/api/v2/customers/actions", body)
print(headers)
# {"X-Timestamp": "1711612200", "X-Signature": "a3f1b9c0..."}

HTTP-Anfragen mit der requests-Bibliothek signieren

Python 3.7+ — HMAC-signierte Anfragen mit der requests-Bibliothek
import hmac
import hashlib
import time
import json
import requests

API_SECRET = b"sk_hmac_9f3a2b7c4d8e1a6f"
BASE_URL = "https://api.billing-service.internal"

def make_signed_request(method: str, path: str, payload: dict) -> requests.Response:
    body = json.dumps(payload, separators=(",", ":"))  # kompaktes JSON, deterministisch
    timestamp = str(int(time.time()))

    signing_string = f"{method}\n{path}\n{timestamp}\n{body}"
    signature = hmac.new(API_SECRET, signing_string.encode(), hashlib.sha256).hexdigest()

    headers = {
        "Content-Type": "application/json",
        "X-Timestamp": timestamp,
        "X-Signature": f"hmac-sha256={signature}",
    }

    try:
        return requests.request(method, f"{BASE_URL}{path}", data=body, headers=headers)
    except requests.RequestException as e:
        raise RuntimeError(f"Signierte Anfrage fehlgeschlagen: {e}") from e

# Signierte POST-Anfrage senden
resp = make_signed_request("POST", "/api/v2/invoices", {
    "customer_id": "cust_4421",
    "line_items": [
        {"description": "Pro plan - März 2026", "amount": 4900},
        {"description": "Zusätzliche Plätze (3)", "amount": 2100},
    ],
})
print(resp.status_code, resp.json())

Wichtiger Hinweis: Verwende separators=(",", ":") beim Serialisieren des Bodys zum Signieren. Das Standard- json.dumps() fügt nach Trennzeichen Leerzeichen ein, was die Byte-Darstellung verändert und die Signatur- Verifizierung bricht, wenn der Server anders serialisiert. Kompaktes JSON liefert eine kanonische Form.

HMAC-Generierung über die Kommandozeile

Manchmal muss ein HMAC berechnet werden, ohne ein Skript zu schreiben. Pythons -c Flag und openssl erledigen das direkt im Terminal.

bash — HMAC-SHA256 via Python-Einzeiler
python3 -c "
import hmac, hashlib
print(hmac.new(b'my_secret', b'message_to_sign', hashlib.sha256).hexdigest())
"
# Ausgabe: 64-stelliger Hex-String
bash — HMAC-SHA256 via openssl (zum Vergleich)
echo -n "message_to_sign" | openssl dgst -sha256 -hmac "my_secret"
# SHA2-256(stdin)= 7d11...

# Datei durch openssl HMAC leiten
openssl dgst -sha256 -hmac "my_secret" < payload.json
bash — HMAC aus Umgebungsvariablen-Schlüssel
# Schlüssel in Umgebungsvariable speichern, um Shell-Verlauf-Exposition zu vermeiden
export HMAC_KEY="sk_live_9f3a2b"
echo -n '{"event":"test"}' | python3 -c "
import hmac, hashlib, sys, os
key = os.environ['HMAC_KEY'].encode()
msg = sys.stdin.buffer.read()
print(hmac.new(key, msg, hashlib.sha256).hexdigest())
"
Hinweis:Das echo -n Flag ist entscheidend — ohne es fügt echo ein Zeilenumbruchzeichen an die Nachricht an, was die HMAC-Ausgabe verändert. Das ist die häufigste Ursache für Signatur-Fehlanpassungen beim Debuggen im Terminal.

Hochleistungsalternative — cryptography-Bibliothek

Für die meisten Anwendungen ist das Standard- hmac Modul schnell genug. Wenn du die cryptography Bibliothek bereits für TLS oder Zertifikatsverarbeitung verwendest, bietet sie ebenfalls HMAC auf Basis von OpenSSL. Der wesentliche praktische Unterschied zur Standardbibliothek ist die ausnahmebasierte .verify() API — sie wirft bei Nichtübereinstimmung eine Ausnahme, anstatt einen booleschen Wert zurückzugeben, den man versehentlich ignorieren könnte.

bash — cryptography installieren
pip install cryptography
Python 3.7+ — HMAC über die cryptography-Bibliothek
from cryptography.hazmat.primitives import hashes, hmac as crypto_hmac

key = b"webhook_signing_key_2026"
message = b'{"event":"subscription.renewed","plan":"enterprise"}'

h = crypto_hmac.HMAC(key, hashes.SHA256())
h.update(message)
signature = h.finalize()  # rohe Bytes

print(signature.hex())
# "9c4e2a..."

# Verifizierungsmodus — wirft InvalidSignature bei Nichtübereinstimmung
h_verify = crypto_hmac.HMAC(key, hashes.SHA256())
h_verify.update(message)
h_verify.verify(signature)  # wirft cryptography.exceptions.InvalidSignature wenn falsch

Die .verify() Methode der cryptography Bibliothek ist besonders praktisch: Sie wirft bei Nichtübereinstimmung eine Ausnahme statt einen booleschen Wert zurückzugeben. Das macht es schwieriger, einen Verifizierungsfehler versehentlich zu ignorieren. Die hmac.compare_digest() Funktion der Standardbibliothek gibt True/ False zurück, was stillschweigend ignoriert werden kann, wenn der Entwickler vergisst, den Rückgabewert zu prüfen.

Terminal-Ausgabe mit Syntax-Hervorhebung

Wenn du HMAC-Signaturen im Terminal debuggst und farbige Ausgabe möchtest, rich erledigt das gut.

bash — rich installieren
pip install rich
Python 3.7+ — farbige HMAC-Ausgabe mit rich
import hmac
import hashlib
from rich.console import Console
from rich.table import Table

console = Console()

key = b"debug_signing_key"
messages = {
    "/api/v2/orders": b'{"status":"active"}',
    "/api/v2/invoices": b'{"status":"pending"}',
    "/api/v2/customers": b'{"status":"verified"}',
}

table = Table(title="HMAC-SHA256 Signaturen")
table.add_column("Endpunkt", style="cyan")
table.add_column("Signatur (erste 32 Zeichen)", style="green")

for endpoint, body in messages.items():
    sig = hmac.new(key, body, hashlib.sha256).hexdigest()
    table.add_row(endpoint, sig[:32] + "...")

console.print(table)
Hinweis:Rich ist nur für die Terminal-Anzeige. Verwende es nicht, wenn HMAC-Signaturen in Dateien, HTTP-Header oder Log-Aggregationssysteme geschrieben werden — die ANSI-Escape-Codes korrumpieren die Ausgabe.

Große Dateien verarbeiten — inkrementelles HMAC

Bei Dateien über etwa 50 MB ist es verschwenderisch, alles in den Speicher zu laden, nur um ein HMAC zu berechnen. Die .update() Methode des HMAC-Objekts erlaubt es, Daten in Blöcken zu verarbeiten. Damit bleibt der Speicherverbrauch unabhängig von der Dateigröße konstant.

Python 3.7+ — HMAC einer großen Datei in Blöcken
import hmac
import hashlib

def hmac_file(key: bytes, filepath: str, chunk_size: int = 8192) -> str:
    """HMAC-SHA256 einer Datei berechnen, ohne sie vollständig in den Speicher zu laden."""
    h = hmac.new(key, digestmod=hashlib.sha256)

    try:
        with open(filepath, "rb") as f:
            while True:
                chunk = f.read(chunk_size)
                if not chunk:
                    break
                h.update(chunk)
    except OSError as e:
        raise OSError(f"Datei '{filepath}' kann nicht gelesen werden: {e}") from e

    return h.hexdigest()

# 2-GB-Datenbankexport signieren
signing_key = b"backup_integrity_key_2026"
signature = hmac_file(signing_key, "/var/backups/db-export-2026-03.sql.gz")
print(f"HMAC-SHA256: {signature}")
Python 3.7+ — HMAC-Signatur einer heruntergeladenen Datei verifizieren
import hmac
import hashlib

def verify_file_hmac(key: bytes, filepath: str, expected_hex: str) -> bool:
    """Die HMAC-SHA256-Signatur einer Datei verifizieren."""
    h = hmac.new(key, digestmod=hashlib.sha256)

    with open(filepath, "rb") as f:
        for chunk in iter(lambda: f.read(65536), b""):
            h.update(chunk)

    return hmac.compare_digest(h.hexdigest(), expected_hex)

# Heruntergeladenes Artefakt verifizieren
is_valid = verify_file_hmac(
    key=b"release_signing_key",
    filepath="/tmp/release-v3.2.0.tar.gz",
    expected_hex="8e3a1f9b2c4d6e7f0a1b3c5d7e9f0a2b4c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f",
)
print(f"Dateiintegrität: {'gültig' if is_valid else 'BESCHÄDIGT'}")
Hinweis:Wechsle zu geblockt verarbeitetem HMAC, wenn die Datei 50–100 MB überschreitet oder wenn Uploads in einem Webserver verarbeitet werden, bei dem der Speicher pro Anfrage wichtig ist. Der .update() Ansatz verwendet unabhängig von der Dateigröße einen festen chunk_size an Speicher. Als Standard werden 64 KB Blöcke empfohlen — groß genug, um Syscall-Overhead zu amortisieren, klein genug, um im L2-Cache der meisten Hardware zu bleiben.

Kryptografisch sichere HMAC-Schlüssel in Python generieren

Ein schwacher oder vorhersehbarer Schlüssel untergräbt die gesamte HMAC-Konstruktion. Das secrets Modul (Python 3.6+) liefert kryptografisch starke Zufallsbytes. Für HMAC-SHA256 verwende einen 32-Byte-Schlüssel. Für HMAC-SHA512 verwende 64 Bytes. Diese entsprechen der internen Blockgröße der jeweiligen Hash-Algorithmen, was die optimale Schlüssellänge gemäß RFC 2104 ist.

Python 3.7+ — HMAC-Schlüssel mit secrets generieren
import secrets

# Schlüssel passend zur Blockgröße des Hash-Algorithmus generieren
sha256_key = secrets.token_bytes(32)   # 256 Bits — für HMAC-SHA256
sha512_key = secrets.token_bytes(64)   # 512 Bits — für HMAC-SHA512

# Hex-Darstellung — sicher für Konfigurationsdateien und Umgebungsvariablen
print(f"HMAC-SHA256-Schlüssel: {sha256_key.hex()}")
# z. B. "a3f1b9c04e7d2f8a1b3c5d7e9f0a2b4c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f"

print(f"HMAC-SHA512-Schlüssel: {sha512_key.hex()}")
# 128-stelliger Hex-String

# URL-sicheres Base64 — kompakt, sicher für HTTP-Header
import base64
b64_key = base64.urlsafe_b64encode(sha256_key).decode("ascii")
print(f"Base64-Schlüssel: {b64_key}")
# z. B. "o_G5wE59L4obPF1-nwortG2ODwobPExdXnqLnA0dLi8="
Warnung:Verwende niemals random.random() oder random.randbytes() aus dem random Modul für HMAC-Schlüssel. Das Standard- random Modul verwendet den Mersenne-Twister-PRNG, der nach 624 Ausgaben vorhersagbar ist. Verwende immer secrets.token_bytes() für sicherheitssensitive Zufälligkeit.

Schlüssellänge und RFC 2104-Anforderungen

RFC 2104 legt fest, dass der HMAC-Schlüssel beliebig lang sein kann, empfiehlt aber mindestens L Bytes — wobei L die Ausgabelänge der zugrunde liegenden Hash-Funktion ist. Für HMAC-SHA256 sind das 32 Bytes (256 Bits). Schlüssel kürzer als L Bits reduzieren die Sicherheitsmarge proportional. Schlüssel länger als die Blockgröße des Hashs (64 Bytes für SHA-256, 128 Bytes für SHA-512) werden zunächst auf die Blockgröße gehasht, sodass es keinen Vorteil bringt, Schlüssel länger als die Blockgröße zu verwenden. Bleib bei 32 Bytes für HMAC-SHA256 und 64 Bytes für HMAC-SHA512.

Sichere Schlüsselspeicherung und -rotation

Hardcode niemals HMAC-Schlüssel im Quellcode. Der Standardansatz für Produktiv- deployments ist, den Schlüssel beim Start aus einer Umgebungsvariable zu laden: os.environ["HMAC_SECRET"].encode(). Für Umgebungen mit höheren Sicherheitsanforderungen speichere Schlüssel in einem Secrets-Management-System wie AWS Secrets Manager, HashiCorp Vault oder GCP Secret Manager und lade sie zur Laufzeit. Diese Systeme bieten Audit-Logs, Zugriffskontrollen und automatische Rotation ohne Code-Deployment.

Plane Schlüsselrotation von Anfang an ein. Bei einer Schlüsselrotation gibt es ein Zeitfenster, in dem laufende Anfragen mit dem alten Schlüssel signiert wurden und bei der Verifizierung gegen den neuen Schlüssel fehlschlagen. Die Standardmaßnahme ist eine kurze Überlappungsphase: Signaturen sowohl des alten als auch des neuen Schlüssels für kurze Zeit (Minuten bis Stunden) akzeptieren, dann den alten Schlüssel außer Betrieb nehmen. Wenn ein Schlüssel kompromittiert wurde — in Logs exponiert, durch einen Git-Commit durchgesickert oder bei einem Sicherheitsvorfall offengelegt — sofort rotieren und alle mit dem kompromittierten Schlüssel erzeugten Signaturen als nicht vertrauenswürdig behandeln. Gecachte Verifizierungsergebnisse neu prüfen und nachgelagerte Konsumenten über die Schlüsseländerung benachrichtigen.

bytearray und memoryview mit hmac.new() verwenden

Die hmac.new() Funktion akzeptiert für die key- und msg-Parameter jedes bytes-artige Objekt. Das bedeutet, du kannst bytes, bytearray oder memoryview direkt übergeben, ohne zu kopieren oder zu konvertieren. Das ist am wichtigsten in zwei Szenarien: Netzwerkprotokoll-Implementierungen, bei denen socket.recv_into() Daten in einen vorab allokierten bytearray Puffer schreibt, und Hochdurchsatz-Systemen, bei denen das Vermeiden von Zwischenkopien den GC-Druck reduziert. Ein memoryview Slice ist kopierlos: Er stellt ein Fenster in den ursprünglichen Puffer bereit, ohne neuen Speicher zu allozieren. Bei zehntausenden von Nachrichten pro Sekunde macht das Eliminieren dieser Allokationen einen messbaren Unterschied in Latenz und Durchsatz.

Python 3.7+ — bytearray und memoryview mit HMAC
import hmac
import hashlib

# bytearray — veränderliche Bytes, nützlich für binäre Protokollpuffer
key = bytearray(b"protocol_signing_key")
frame = bytearray(b'\x01\x02\x03\x04payload_data_here')

sig = hmac.new(key, frame, hashlib.sha256).hexdigest()
print(f"Frame-Signatur: {sig[:32]}...")

# memoryview — kopierloser Ausschnitt eines größeren Puffers
large_buffer = bytearray(4096)
large_buffer[:20] = b"sensor_reading_12345"

# HMAC nur der ersten 20 Bytes ohne Kopieren
view = memoryview(large_buffer)[:20]
sig = hmac.new(key, view, hashlib.sha256).hexdigest()
print(f"Sensor-Signatur: {sig[:32]}...")

Häufige Fehler

Die ersten beiden Fehler sehe ich in fast jedem Code-Review von Webhook-Handlern. Sie sind leicht unter Zeitdruck einzuführen und schwer zu erkennen, wenn man nicht weiß, worauf man achten muss.

HMAC-Signaturen mit == statt hmac.compare_digest() vergleichen

Problem: Der ==-Operator schließt beim ersten Byte-Unterschied kurz und gibt Timing-Informationen preis, die es einem Angreifer ermöglichen, die erwartete Signatur schrittweise zu rekonstruieren.

Lösung: Immer hmac.compare_digest() für Signaturvergleiche verwenden — es läuft in konstanter Zeit, unabhängig davon, wo die Nichtübereinstimmung auftritt.

Before · Python
After · Python
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()

if received_sig == expected_sig:  # ANFÄLLIG für Timing-Angriff
    process_webhook(body)
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()

if hmac.compare_digest(received_sig, expected_sig):  # zeitkonstant
    process_webhook(body)
Einen String statt Bytes an hmac.new() übergeben

Problem: hmac.new() erfordert bytes-artige Objekte. Das Übergeben eines Python-str wirft TypeError: "key: expected bytes or bytearray, but got 'str'".

Lösung: Für String-Schlüssel und Nachrichten .encode() aufrufen, bevor sie an hmac.new() übergeben werden.

Before · Python
After · Python
key = "my_api_secret"  # str, nicht bytes
msg = '{"event":"test"}'  # str, nicht bytes
sig = hmac.new(key, msg, hashlib.sha256)  # TypeError!
key = "my_api_secret"
msg = '{"event":"test"}'
sig = hmac.new(key.encode(), msg.encode(), hashlib.sha256)
digestmod vergessen (Python 3.4+)

Problem: Der Aufruf von hmac.new(key, msg) ohne das dritte Argument wirft TypeError. Vor Python 3.4 war MD5 der Standard, aber der Standard wurde aus Sicherheitsgründen entfernt.

Lösung: Den Algorithmus immer explizit übergeben: hashlib.sha256, hashlib.sha512 oder was das Protokoll erfordert.

Before · Python
After · Python
# Fehlendes digestmod — wirft TypeError in Python 3.4+
sig = hmac.new(key, msg).hexdigest()
# Hash-Algorithmus immer angeben
sig = hmac.new(key, msg, hashlib.sha256).hexdigest()
.hexdigest() verwenden, wenn der Anbieter Base64 erwartet

Problem: Viele Webhook-Anbieter (Stripe, Shopify) senden Base64-kodierte Signaturen, kein Hex. Der Vergleich eines Hex-Strings mit einem Base64-Wert schlägt immer fehl und führt dazu, dass alle Webhooks abgelehnt werden.

Lösung: Die Anbieterdokumentation auf das Signaturformat prüfen. Bei Base64 die rohen .digest()-Bytes kodieren, nicht den .hexdigest()-String.

Before · Python
After · Python
# Anbieter sendet Base64, wir berechnen Hex — stimmt nie überein
expected = hmac.new(key, body, hashlib.sha256).hexdigest()
# "a3f1b9c0..."  vs  "o/G5wE59..."  — immer Nichtübereinstimmung
import base64
# Format des Anbieters verwenden: rohe Bytes → Base64
raw = hmac.new(key, body, hashlib.sha256).digest()
expected = base64.b64encode(raw).decode("ascii")
# "o/G5wE59..."  — stimmt mit dem Header überein

stdlib hmac vs cryptography — Kurzvergleich

Methode
Algorithmus
Ausgabe
Streaming
Eigene Typen
Installation
hmac.new() + hexdigest()
Beliebig (hashlib)
Hex-String
✓ via .update()
N/A
Nein (stdlib)
hmac.new() + digest()
Beliebig (hashlib)
Rohe Bytes
✓ via .update()
N/A
Nein (stdlib)
hmac.digest()
Beliebig (hashlib)
Rohe Bytes
✗ (einmalig)
N/A
Nein (stdlib, 3.7+)
hashlib.sha256 (einfacher Hash)
Nur SHA-256
Hex oder Bytes
✓ via .update()
N/A
Nein (stdlib)
cryptography (HMAC)
Beliebig
Rohe Bytes
✓ via .update()
N/A
pip install
pyca/cryptography + CMAC
AES-CMAC
Rohe Bytes
✓ via .update()
N/A
pip install

Das stdlib- hmac Modul für Webhook-Verifizierung, API-Signierung und allgemeine HMAC-Operationen verwenden — es erfordert keine Abhängigkeiten und deckt jeden Standard-Algorithmus ab. Für Batch-Operationen, bei denen die einmalige Geschwindigkeit wichtig ist, hmac.digest() verwenden. Die cryptography Bibliothek nur einsetzen, wenn sie bereits für andere Operationen (TLS, X.509, symmetrische Verschlüsselung) benötigt wird und die ausnahmebasierte .verify() API erwünscht ist. Für schnelle Signaturprüfungen ohne Python-Code nutze den HMAC-Generator, um Schlüssel und Nachricht einzufügen und sofort das Ergebnis zu erhalten.

Häufig gestellte Fragen

Was ist der Unterschied zwischen hmac.new() und hmac.digest() in Python?

hmac.new() gibt ein HMAC-Objekt zurück, das inkrementelle .update()-Aufrufe unterstützt und sowohl .digest() (rohe Bytes) als auch .hexdigest() (Hex-String) bereitstellt. hmac.digest() ist eine einmalige Funktion, die in Python 3.7 hinzugefügt wurde und rohe Bytes direkt zurückgibt, ohne ein Zwischenobjekt zu erzeugen. Verwende hmac.digest(), wenn du die vollständige Nachricht hast und nur das Ergebnis benötigst. Verwende hmac.new(), wenn du Daten in Blöcken verarbeiten oder eine Hex-Ausgabe benötigst.

Python
import hmac, hashlib

key = b"webhook_secret_2026"
body = b'{"event":"payment.completed","amount":9950}'

# Einmalig — gibt rohe Bytes zurück
raw = hmac.digest(key, body, hashlib.sha256)

# Objekt-basiert — unterstützt inkrementelle Updates und Hex-Ausgabe
h = hmac.new(key, body, hashlib.sha256)
hex_sig = h.hexdigest()

Wie verifiziere ich eine HMAC-Signatur in Python?

Berechne den HMAC der ursprünglichen Nachricht mit dem gemeinsamen Geheimnis neu und vergleiche dann mit hmac.compare_digest(). Verwende niemals == für den Signaturvergleich. Der ==-Operator schließt beim ersten nicht übereinstimmenden Byte kurz und gibt so Informationen über die erwartete Signaturlänge und den Inhalt preis.

Python
import hmac, hashlib

def verify_signature(secret: bytes, message: bytes, received_sig: str) -> bool:
    expected = hmac.new(secret, message, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received_sig)

Ist Python hmac SHA-256 dasselbe wie ein Hash mit hashlib.sha256?

Nein. hashlib.sha256 berechnet einen einfachen SHA-256-Hash der Eingabe, den jeder reproduzieren kann. HMAC-SHA256 mischt gemäß RFC 2104 einen geheimen Schlüssel in die Hash-Berechnung ein, sodass nur jemand mit dem Schlüssel die korrekte Ausgabe erzeugen oder verifizieren kann. Ein einfacher Hash beweist die Datenintegrität. Ein HMAC beweist sowohl Integrität als auch Authentizität.

Python
import hmac, hashlib

msg = b"transfer:9950:USD"
key = b"api_secret_k8x2"

plain_hash = hashlib.sha256(msg).hexdigest()  # jeder kann das berechnen
hmac_hash = hmac.new(key, msg, hashlib.sha256).hexdigest()  # erfordert den Schlüssel

Kann ich HMAC-SHA1 in Python 3 verwenden?

Ja, übergib hashlib.sha1 als digestmod-Argument. HMAC-SHA1 funktioniert in Python 3 problemlos, und das hmac-Modul zeigt dafür keine Deprecation-Warnungen. Dennoch gilt SHA-1 für neue Entwürfe als schwach — seine Kollisionsresistenz liegt unter 80 Bit und NIST hat es 2015 für die meisten digitalen Signaturanwendungen als veraltet erklärt. Der Hauptgrund für HMAC-SHA1 heute ist die Abwärtskompatibilität mit bestehenden Protokollen, die es vorschreiben, wie OAuth 1.0a oder bestimmte ältere Webhook-Systeme. Wenn du beide Seiten der Integration kontrollierst, bevorzuge für neue Projekte HMAC-SHA256 oder HMAC-SHA512.

Python
import hmac, hashlib

key = b"oauth_consumer_secret"
base_string = b"GET&https%3A%2F%2Fapi.example.com&oauth_nonce%3Dabc123"
sig = hmac.new(key, base_string, hashlib.sha1).digest()

Wie generiere ich einen sicheren HMAC-Schlüssel in Python?

Verwende secrets.token_bytes() aus der Standardbibliothek. Für HMAC-SHA256 ist ein 32-Byte-Schlüssel die Standardempfehlung, da er der Hash-Blockgröße entspricht. Für HMAC-SHA512 verwende 64 Bytes. Verwende nicht random.random() oder os.urandom() für die Schlüsselgenerierung in Anwendungscode — secrets ist das richtige Modul für sicherheitssensitive Zufälligkeit seit Python 3.6.

Python
import secrets

hmac_sha256_key = secrets.token_bytes(32)  # 256 Bits
hmac_sha512_key = secrets.token_bytes(64)  # 512 Bits

# Als Hex für Konfigurationsdateien speichern
print(hmac_sha256_key.hex())
# z. B. "a3f1b9c04e..."

Warum erfordert hmac.new() digestmod in Python 3?

Vor Python 3.4 war der Standardwert von digestmod MD5, das kryptografisch gebrochen ist — MD5 hat bekannte Kollisionsangriffe und sollte niemals in neuem sicherheitssensitivem Code verwendet werden. Die Python-Maintainer haben den Standard entfernt, um eine explizite Algorithmuswahl zu erzwingen und zu verhindern, dass Entwickler versehentlich MD5-basierte MACs ausliefern. Wenn du hmac.new(key, msg) ohne digestmod aufrufst, erhältst du einen TypeError. Übergib den Algorithmus immer explizit: hashlib.sha256, hashlib.sha512 oder einen anderen hashlib-Konstruktor. Im Zweifelsfall ist hashlib.sha256 die sichere Wahl — keine bekannten Schwachstellen und schnell genug für jede praktische Arbeitslast.

Python
import hmac, hashlib

key = b"secret"
msg = b"data"

# Wirft TypeError in Python 3.4+
# hmac.new(key, msg)  # TypeError: missing required argument: 'digestmod'

# Algorithmus immer angeben
h = hmac.new(key, msg, hashlib.sha256)

Für eine schnelle HMAC-Prüfung ohne ein Python-Skript zu starten, füge deinen Schlüssel und deine Nachricht in den Online-HMAC-Generator ein — er unterstützt SHA-256, SHA-384 und SHA-512 mit sofortigen Ergebnissen.

Verwandte Tools

DV
Dmitri VolkovDevOps Engineer & Python Automation Specialist

Dmitri is a DevOps engineer who relies on Python as his primary scripting and automation language. He builds internal tooling, CI/CD pipelines, and infrastructure automation scripts that run in production across distributed teams. He writes about the Python standard library, subprocess management, file processing, encoding utilities, and the practical shell-adjacent Python that DevOps engineers use every day.

MS
Maria SantosTechnischer Prüfer

Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.