Sicherung der Server‑zu‑Server‑Integrität mit HMAC‑Signaturen in Django/DRF
Wenn Server miteinander kommunizieren, stellt sich die Frage: „Ist die Anfrage wirklich von mir?“ und „Wurde sie unterwegs verändert?“ In diesem Beitrag zeigen wir, wie man in einer Django/DRF‑Umgebung HMAC‑basierte Authentifizierung einsetzt, um die Integrität und Vertrauenswürdigkeit von Server‑zu‑Server‑Anfragen zu gewährleisten.
Insbesondere werden wir erläutern:
- Was ist das Ziel dieser Technik?
- Welche Angriffe kann sie verhindern?
- Warum sie für Client‑Server‑Kommunikation ungeeignet ist (Grenzen)
- Wie man
hmac_mixin.py+ CBV in einem realen Django/DRF‑Projekt einsetzt
Was ist HMAC‑Signatur‑Authentifizierung?
HMAC (Hash‑based Message Authentication Code) ist ein Verfahren, bei dem ein geheimer Schlüssel + Nachricht verwendet wird, um einen Signaturwert (signature) zu erzeugen.
- Zwei Server (A, B) teilen sich einen secret key.
- Server A sendet eine
POST‑Anfrage an Server B: - Der Body und ein Timestamp werden zu einer HMAC‑Signatur zusammengefasst.
- Diese Signatur wird in einem HTTP‑Header (z. B.
X-HMAC-Signature) mitgeschickt. - Server B berechnet mit demselben secret key die Signatur erneut und vergleicht sie:
- Gleich → „Dies ist eine legitime Anfrage von A“
- Ungleich → „Die Anfrage wurde verändert oder gefälscht“
Damit prüft HMAC gleichzeitig:
- Integrität – Der Inhalt wurde nicht verändert.
- Authentifizierung – Nur derjenige, der den geheimen Schlüssel kennt, kann die Signatur erzeugen.
※ Voraussetzung: Der geheime Schlüssel darf ausschließlich zwischen den Servern geteilt werden.
Zweck der Technik und zu verhindende Angriffe
1. Verhinderung von Body‑Manipulation
Angenommen, ein Angreifer fängt den Datenverkehr ab. Er könnte:
- Den Body leicht verändern, um z. B. Geld auf ein anderes Konto zu überweisen.
- Parameter ändern, um höhere Beträge oder andere Optionen zu nutzen.
Der empfangende Server berechnet erneut die HMAC‑Signatur. Sobald sich der Body um einen einzigen Buchstaben ändert, verschwindet die Signatur, und die Anfrage wird abgelehnt.
2. Verhinderung von Server‑Spoofing
Ein Angreifer, der vorgibt, ein legitimer Server zu sein, kann ohne den geheimen Schlüssel keine gültige Signatur erzeugen. Der empfangende Server erkennt dies sofort.
3. Schutz vor Replay‑Angriffen (Timestamp/Nonce)
Ein Angreifer könnte eine gültige Anfrage einfach erneut senden. Deshalb fügen wir häufig einen Timestamp (X-HMAC-Timestamp) oder einen Nonce hinzu und prüfen:
- Ist die Anfrage zu alt? → Ablehnen.
- Wurde der Nonce bereits verwendet? → Ablehnen.
Damit wird Replay‑Angriff reduziert.
※ HMAC allein löst nicht alle Probleme – HTTPS/TLS bleibt die Basis.
Warum HMAC nicht für Client‑Server‑Kommunikation geeignet ist
„Für Client‑Server‑Kommunikation ist HMAC ungeeignet, weil der Schlüssel im Client-Code exponiert werden kann.“
1. Schlüssel kann nicht verborgen werden
- Mobile Apps, SPA‑Frontends (JS), Desktop‑Apps enthalten den Schlüssel im Bundle/JavaScript.
- Ein Angreifer kann die App dekompilieren oder den JS‑Code inspizieren und den Schlüssel extrahieren.
Einmal exponiert, kann der Angreifer beliebige HMAC‑Signaturen erzeugen, und der Server kann nicht mehr unterscheiden, ob die Anfrage vom echten Client oder vom Angreifer stammt.
2. HMAC ist keine Verschlüsselung
HMAC schützt nur die Integrität und Authentifizierung, verschlüsselt jedoch den Body nicht. Sensible Daten müssen weiterhin über TLS geschützt werden.
Wann sollte man HMAC‑basierte Server‑zu‑Server‑Authentifizierung einsetzen?
1. Django‑App → separater DRF‑Auth‑Server
- Mehrere Services nutzen einen gemeinsamen Auth‑/User‑Server (DRF).
- Die Haupt‑Django‑App sendet
POST‑Anfragen an den Auth‑Server. - Durch HMAC‑Signatur kann der Auth‑Server sicherstellen, dass die Anfrage von der vertrauenswürdigen Django‑App stammt.
2. Django‑App → AI‑Inference‑Server (DRF, FastAPI, etc.)
- Die Django‑App fungiert als Front‑/Back‑End.
- Schwergewichtige AI‑Inference‑Aufgaben werden an einen separaten Server delegiert.
- Durch HMAC‑Signatur wird die interne Kommunikation gesichert und gefälschte Anfragen verhindert.
Praktisches Pattern in Django/DRF: hmac_mixin.py + CBV
Ein sauberer Ansatz in Projekten:
- Lege
hmac_mixin.pyim Projekt‑/App‑Verzeichnis an. - Extrahiere die gemeinsame HMAC‑Signatur‑Logik als Mixin.
- Erstelle CBVs, die den Mixin erben und
post_with_hmacaufrufen.
1. hmac_mixin.py – Gemeinsame Signatur + POST‑Methode
# hmac_mixin.py
import hmac
import hashlib
import json
import time
import requests
from django.conf import settings
class HMACRequestMixin:
# settings.py: HMAC_SECRET_KEY = "super-secret-key-from-env"
HMAC_SECRET_KEY = settings.HMAC_SECRET_KEY.encode("utf-8")
HMAC_HEADER_NAME = "X-HMAC-Signature"
HMAC_TIMESTAMP_HEADER = "X-HMAC-Timestamp"
HMAC_ALGORITHM = hashlib.sha256
def build_hmac_signature(self, body: bytes, timestamp: str) -> str:
"""Erzeugt die HMAC‑Signatur aus Body und Timestamp."""
message = timestamp.encode("utf-8") + b"." + body
digest = hmac.new(self.HMAC_SECRET_KEY, message, self.HMAC_ALGORITHM).hexdigest()
return digest
def post_with_hmac(self, url: str, payload: dict, timeout: int = 5):
"""Sendet eine HMAC‑signierte POST‑Anfrage an die gegebene URL."""
body = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
timestamp = str(int(time.time()))
signature = self.build_hmac_signature(body, timestamp)
headers = {
"Content-Type": "application/json",
self.HMAC_HEADER_NAME: signature,
self.HMAC_TIMESTAMP_HEADER: timestamp,
}
response = requests.post(url, data=body, headers=headers, timeout=timeout)
response.raise_for_status()
return response
2. Beispiel‑CBV für den Sender
# views.py
from django.conf import settings
from django.http import JsonResponse
from django.views import View
from .hmac_mixin import HMACRequestMixin
class AIInferenceRequestView(HMACRequestMixin, View):
"""Empfängt Client‑Anfrage, sendet HMAC‑signierte Anfrage an AI‑Server."""
def post(self, request, *args, **kwargs):
data = json.loads(request.body.decode("utf-8"))
payload = {
"text": data.get("text", ""),
"user_id": request.user.id if request.user.is_authenticated else None,
}
url = settings.AI_SERVER_URL # z. B. "https://ai-service.internal/v1/infer"
try:
ai_response = self.post_with_hmac(url, payload)
except requests.RequestException as e:
return JsonResponse({"detail": "AI server error", "error": str(e)}, status=502)
return JsonResponse(ai_response.json(), status=ai_response.status_code)
Empfänger‑Seite: HMAC‑Authentifizierungs‑Klasse in DRF
# authentication.py
import hmac
import hashlib
import time
from django.conf import settings
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class HMACSignatureAuthentication(BaseAuthentication):
SECRET_KEY = settings.HMAC_SECRET_KEY.encode("utf-8")
HMAC_HEADER_NAME = "X-HMAC-Signature"
HMAC_TIMESTAMP_HEADER = "X-HMAC-Timestamp"
ALGORITHM = hashlib.sha256
MAX_SKEW_SECONDS = 60
def _build_signature(self, body: bytes, timestamp: str) -> str:
message = timestamp.encode("utf-8") + b"." + body
return hmac.new(self.SECRET_KEY, message, self.ALGORITHM).hexdigest()
def authenticate(self, request):
signature = request.headers.get(self.HMAC_HEADER_NAME)
timestamp = request.headers.get(self.HMAC_TIMESTAMP_HEADER)
if not signature or not timestamp:
raise AuthenticationFailed("Missing HMAC headers")
try:
ts = int(timestamp)
except ValueError:
raise AuthenticationFailed("Invalid timestamp")
now = int(time.time())
if abs(now - ts) > self.MAX_SKEW_SECONDS:
raise AuthenticationFailed("Request timestamp too old")
expected_signature = self._build_signature(request.body, timestamp)
if not hmac.compare_digest(signature, expected_signature):
raise AuthenticationFailed("Invalid HMAC signature")
return (None, None)
Anwendung in einer DRF‑View
# views.py (DRF‑Server)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from .authentication import HMACSignatureAuthentication
class AIInferenceView(APIView):
authentication_classes = [HMACSignatureAuthentication]
permission_classes = [AllowAny]
def post(self, request, *args, **kwargs):
input_text = request.data.get("text", "")
result = {"answer": f"AI result for: {input_text}"}
return Response(result)
Damit haben Sie ein klares Muster:
- Sender:
HMACRequestMixin→post_with_hmac - Empfänger:
HMACSignatureAuthentication→ Validierung
Fazit
- HMAC‑Signaturen nutzen einen gemeinsamen geheimen Schlüssel, um Integrität und Authentifizierung von Server‑zu‑Server‑Anfragen zu prüfen.
- Sie verhindern Body‑Manipulation, Server‑Spoofing und Replay‑Angriffe (mit Timestamp/Nonce).
- Für Client‑Server‑Kommunikation ist HMAC ungeeignet, da der Schlüssel im Client-Code exponiert werden kann.
- In Django/DRF‑Projekten empfiehlt sich die Verwendung eines Mixins (
hmac_mixin.py) für das Senden und einer eigenen Authentifizierungs‑Klasse für das Empfangen.

Es sind keine Kommentare vorhanden.