import ApiLink from '@site/src/components/ApiLink'
Der FIT-Connect Zustelldienst informiert sendende und empfangende Systeme (API-Clients) aktiv über [neue Einreichungen](../getting-started/receiving/query.mdx) oder [Statusupdates](../getting-started/sending/query-status.mdx).
Hierzu werden HTTP-Callbacks genutzt, die auch als [Webhooks](https://de.wikipedia.org/wiki/WebHooks) bezeichnet werden.
Webhooks ermöglichen es, API-Clients aktiv über diese Ereignisse zu informieren ohne dass eine regelmäßige Abfrage ([Polling](https://de.wikipedia.org/wiki/Polling_(Informatik))) nötig wäre.
Technisch werden Webhooks als HTTP-POST-Request realisiert.
Im Folgenden verwenden wir die Begriffe *Callback* und *Webhook* synonym.
## Callback-URL
API-Clients stellen zum Empfang von Callbacks einen HTTP-Endpunkt bereit, an den der Zustelldienst einen HTTP-POST-Request übermitteln kann.
API-Clients müssen auf eingehende Callbacks mit einer HTTP-Response mit Status Code `200 OK` antworten.
Die URL dieses HTTP-Endpunkts bezeichnen wir als Callback-URL (`callbackUrl`).
Sie wird von dem an FIT-Connect angebundenen System festgelegt.
Eine solche Callback-URL kann z.B. wie folgt aussehen:
Die Callback-URL **DARF NUR** über HTTPS erreichbar sein.
Der Zustelldienst wird Callbacks nur über eine via HTTPS verschlüsselte Verbindung auslösen.
## Konfiguration von Callbacks
Eine Konfiguration von Callbacks ist [über das Self-Service-Portal](../getting-started/receiving/destination.mdx) und über die API-Endpunkte <ApiLink to="/destinations/{destinationId}" withMethod="put" /> bzw. <ApiLink to="/destinations/{destinationId}" withMethod="patch" /> möglich.
Bei der Konfiguration werden die *Callback-URL* und ein *Callback-Secret* vom API-Client festgelegt.
Das *Callback-Secret* dient der Überprüfung der Echtheit (Authentizität) von eingehenden Callbacks (siehe nächster Abschnitt).
Das angegebene *Callback-Secret* kann über die API nur geschrieben und aktualisiert, aber nicht gelesen werden und **DARF NICHT** an Dritte weitergegeben werden.
Ein sicheres *Callback-Secret* kann über die folgenden Aufrufe erzeugt werden:
API-Clients, die Callbacks empfangen, **MÜSSEN** zwingend sicherstellen, dass ausgelöste Callbacks von einem vertrauenswürdigen Zustelldienst stammen.
Hierzu enthalten Callbacks einen Message Authentication Code (HMAC) gemäß [RFC 2104](https://datatracker.ietf.org/doc/html/rfc2104) auf Basis des angegebenen *Callback-Secrets*.
Ein Message Athentication Code kann als „symmetrische Signatur“ verstanden werden und ermöglicht die Prüfung der Herkunft und Integrität eines eingehende Callbacks.
Der Message Authentication Code wird im HTTP-Header `callback-authentication` übertragen.
Um [Replay-Angriffe](https://de.wikipedia.org/wiki/Replay-Angriff) zu vermeiden, enthält der Message Authentication Code einen aktuellen Timestamp.
Dieser Timestamp wird im HTTP-Header `callback-timestamp` übertragen.
Bei der Prüfung der Echtheit des ausgelösten Callbacks **MÜSSEN** API-Clients prüfen, dass der angegebene Timestamp nicht älter als **5 Minuten** ist.
Das folgende Beispiel zeigt die Verwendung der HTTP-Header `callback-authentication` und `callback-timestamp`:
Der HMAC wird gebildet aus dem im HTTP-Header `callback-timestamp` übertragenen Zeitstempel und dem im HTTP-Body übertragenen Payload, getrennt durch das Zeichen `.` (Punkt), jeweils UTF-8-kodiert.
Um den Message Authentication Code (HMAC) zu verifizieren, bildet der API-Client mit Hilfe des *Callback Secret* den HMAC nach und vergleicht diesen mit dem im HTTP-Header `callback-authentication` übertragenen HMAC.
Bei der Prüfung **MÜSSEN** die folgenden Implementierungshinweise zwingend zu beachten:
- Das Callback Secret **MUSS** in API-Clients konfigurierbar sein und **DARF NICHT** fest im Quellcode eines API-Clients einprogrammiert sein.
- Dies kann beispielsweise durch die Konfiguration des Callback Secret in einer Konfigurationsdatei oder über eine Umgebungsvariable (`$ export CALLBACK_SECRET=your_secret`) erreicht werden.
- Bei der Erzeugung des HMAC **MUSS** der Hash-Algorithmus `SHA-512` verwendet werden.
- Es **MUSS** geprüft werden, dass der angegebene Zeitstempel nicht älter als **5 Minuten** ist.
- Beim Vergleich des übertragenen HMAC und des vom API-Client gebildeteten HMAC **MUSS** ein zeitlich konstanter Zeichenfolgenvergleich (*constant time string comparison*) verwendet werden.
- In Python kann dies über die Verwendung der Methode [`hmac.compare_digest`](https://docs.python.org/2/library/hmac.html#hmac.compare_digest) erreicht werden.
- In Ruby kann dies über die Verwendung der Methode [`secure_compare`](https://rubydoc.info/github/rack/rack/master/Rack/Utils:secure_compare) erreicht werden.
- Callbacks mit ungültigem Message Authentication Code **MÜSSEN** von API-Clients ignoriert/verworfen werden.
Dabei ist zunächst der Zeitstempel (`callback-timestamp`-Header) und anschließend der HMAC (`callback-authentication`-Header) zu prüfen:
```python
# 1. Timestamp überprüfen
current_time_epoch = int(time.time())
seconds_five_minutes = 60 * 5
if current_time_epoch - request['headers']['callback-timestamp'] > seconds_five_minutes:
# 3. Berechneten HMAC mit HMAC aus HTTP-Header vergleichen
if not hmac.compare_digest(request['headers']['callback-authentication'], expected_hmac_base64):
print('Error: invalid hmac')
sys.exit(2)
else:
print('hmac ok')
```
Das dargestellte Script findet sich auch zur freien Verwendung im [FIT-Connect-Tools-Repository](https://git.fitko.de/fit-connect/fit-connect-tools/-/blob/main/validate-callback.py).