import ApiLink from '@site/src/components/ApiLink'
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).
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.
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.
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.
...
@@ -13,47 +12,130 @@ Technisch werden Webhooks als HTTP-POST-Request realisiert.
...
@@ -13,47 +12,130 @@ Technisch werden Webhooks als HTTP-POST-Request realisiert.
Im Folgenden verwenden wir die Begriffe *Callback* und *Webhook* synonym.
Im Folgenden verwenden wir die Begriffe *Callback* und *Webhook* synonym.
## Callback-URL
## Callback-URL
Hierzu stellen API-Clients einen HTTP-Endpunkt bereit, an den der Zustelldienst einen HTTP-POST-Request mit übermitteln kann.
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.
Die URL dieses HTTP-Endpunkts (`callbackUrl`) wird von dem an FIT-Connect angebundenen System festgelegt.
Eine solche Callback-URL kann z.B. wie folgt aussehen:
Eine solche Callback-URL kann z.B. wie folgt aussehen:
Die Callback-URL **MUSS** über HTTPS erreichbar sein.
Die Callback-URL **DARF NUR** über HTTPS erreichbar sein.
Der Zustelldienst wird Callbacks nur über eine via HTTPS verschlüsselte Verbindung auslösen.
Der Zustelldienst wird Callbacks nur über eine via HTTPS verschlüsselte Verbindung auslösen.
## Konfiguration von Callbacks
## Konfiguration von Callbacks
TODO: Aushandlung des Callback Secret via API
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.
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 eines geheimen symmetrischen Schlüssels.
Hierzu enthalten Callbacks einen Message Authentication Code (HMAC) gemäß [RFC 2104](https://datatracker.ietf.org/doc/html/rfc2104) auf Basis des angegebenen *Callback-Secrets*.
Der geheime Schlüssel, im Folgenden *Callback Secret* genannt, wird bei der Konfiguration eines Callbacks festgelegt **DARF NICHT** an Dritte weitergegeben werden.
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.
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.
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.
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.
Durch die Prüfung des Message Authentication Code können API-Clients die Herkunft und Integrität eines Callbacks verifizieren.
Das folgende Beispiel zeigt die Verwendung der HTTP-Header `callback-authentication` und `callback-timestamp`:
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).
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.
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.
Dabei sind die folgenden Implementierungshinweise zwingend zu beachten:
Bei der Prüfung **MÜSSEN** die folgenden Implementierungshinweise zwingend zu beachten:
- 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` erreicht werden.
- Das Callback Secret **MUSS** in API-Clients konfigurierbar sein und **DARF NICHT** fest im Quellcode eines API-Clients einprogrammiert sein.
- Das Callback Secret **MUSS** in API-Clients konfigurierbar sein und **DARF NICHT** fest im Quellcode eines API-Clients einprogrammiert sein.
- Callbacks mit ungültigem Message Authentication Code **MÜSSEN** von API-Clients irgnoriert werden.
- 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).