Verwendung von Callbacks
Der FIT-Connect Zustelldienst informiert Onlinedienst und Verwaltungssysteme (API-Clients) aktiv über neue Einreichungen oder Statusupdates. Hierzu werden HTTP-Callbacks genutzt, die auch als Webhooks bezeichnet werden. Webhooks ermöglichen es, API-Clients aktiv über diese Ereignisse zu informieren, ohne dass eine regelmäßige Abfrage (Polling) 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.
Die URL dieses Callback-Endpunkts bezeichnen wir als Callback-URL (callbackUrl
).
Sie wird von dem an FIT-Connect angebundenen System festgelegt.
Der Callback-Endpunkt muss von außen über das Internet erreichbar sein, damit der Zustelldienst Callbacks an diesen Endpunkt senden kann. Der Callback-Endpunkt MUSS zwingend über TLS (HTTPS) abgesichert sein und DARF NICHT ohne Verschlüsselung via HTTP erreichbar sein. Der Zustelldienst wird Callbacks nur über eine via HTTPS verschlüsselte Verbindung auslösen.
API-Clients müssen auf eingehende Callbacks mit einer HTTP-Response mit einem Status Code 2xx Success
antworten (z.B. 200 OK
oder 202 Accepted
).
Eine solche Callback-URL kann z.B. wie folgt aussehen:
https://fachverfahren.beispielstadt.example.org/callbacks/fit-connect
Da der Callback-Endpunkt öffentlich über das Internet erreichbar ist, MÜSSEN angebundene Systeme prüfen, ob eingehende Callbacks von einem vertrauenswürdigen Zustelldienst stammen. Zu diesem Zweck MÜSSEN die im Abschnitt Prüfung von Callbacks beschriebenen Prüfungen durchgeführt werden.
Konfiguration von Callbacks
Eine Konfiguration von Callbacks ist über das Self-Service-Portal und über die API-Endpunkte PUT /v1/destinations/{destinationId}
bzw. PATCH /destinations/{destinationId}
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:
- Python:
python -c 'import secrets; print(secrets.token_urlsafe(32))'
- Ruby:
ruby -rsecurerandom -e 'puts SecureRandom.hex(32)'
- pwgen:
pwgen --secure 64 1
Die Einrichtung von Callbacks im Self-Service-Portal wird im Artikel Zustellpunkt anlegen näher beschrieben.
Konfiguration von Callbacks für Zustellpunkte
Über die API können Callbacks für Zustellpunkte wie folgt konfiguriert werden:
- curl
- Java
- JavaScript
$ SUBMISSION_API=https://submission-api-testing.fit-connect.fitko.dev
$ JWT_TOKEN=...
$ DESTINATION_ID=...
$ CALLBACK_URL=https://fachverfahren.beispielstadt.example.org/callbacks/fit-connect
$ CALLBACK_SECRET=insecure_unsafe_qHScgrg_kP-R31jHUwp3GkVkGJolvBchz65b74Lzue0
$ curl -X PATCH \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $JWT_TOKEN" \
--data "{ \"callback\": { \"url\": \"$CALLBACK_URL\", \"secret\": \"$CALLBACK_SECRET\" }}" \
"$SUBMISSION_API/v1/destinations/$DESTINATION_ID"
TODO: Codebeispiel ergänzen
TODO: Codebeispiel ergänzen
Prüfung von Callbacks
Da der Callback-Endpunkt öffentlich über das Internet erreichbar ist, MÜSSEN angebundene Systeme prüfen, ob eingehende Callbacks von einem vertrauenswürdigen Zustelldienst stammen.
Hierzu enthalten Callbacks einen Message Authentication Code (HMAC) gemäß RFC 2104 auf Basis des angegebenen Callback-Secrets. Ein HMAC kann als „symmetrische Signatur“ verstanden werden und ermöglicht die Prüfung der Herkunft und Integrität eines eingehenden Callbacks.
Der HMAC wird im HTTP-Header callback-authentication
übertragen.
Um Replay-Angriffe zu vermeiden, enthält er 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
.
Zu beachten ist, dass das Feld submissionIds
als deprecated markiert wurde und durch das Feld submissions
ersetzt werden soll.
POST /callbacks/fit-connect
callback-authentication: 2056b372b5bcec06d8f11ab79b84b42d6cbe1c8e1178cdfa36e4385dcf717758aaa7599f417d9ec3e079087884f4fd59680bf713621383e2d4414ef74fb10df3
callback-timestamp: 1672527599
{
"type":"https://schema.fitko.de/fit-connect/submission-api/callbacks/new-submissions",
"submissionIds":["f39ab143-d91a-474a-b69f-b00f1a1873c2"],
"submissions":[
{
"destinationId":"d12caea8-f372-4eb1-b102-b0a228253a11",
"submissionId":"f39ab143-d91a-474a-b69f-b00f1a1873c2",
"caseId":"9eec7d3e-dc66-4f82-9f52-1520bf96a32e"
}
]
}
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. Der HMAC wird hexadezimal kodiert übertragen.
Als Hash-Algorithmus wird SHA-512 verwendet.
callback-authentication = HEX(HMAC(key={callback-secret}, message={timestamp}.{http-body}))
Um den HMAC zu verifizieren, bildet der API-Client mithilfe 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 beachtet werden:
- 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.
- Dies kann beispielsweise durch die Konfiguration des Callback Secret in einer Konfigurationsdatei oder über eine Umgebungsvariable (
- 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 gebildeten 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. - In Ruby kann dies über die Verwendung der Methode
secure_compare
erreicht werden.
- In Python kann dies über die Verwendung der Methode
- Callbacks mit ungültigem HMAC MÜSSEN von API-Clients ignoriert werden.
Dabei ist zunächst
- der Zeitstempel (
callback-timestamp
-Header) und anschließend - der HMAC (
callback-authentication
-Header) zu prüfen:
# 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:
print('Error: timestamp too old')
sys.exit(1)
else:
print('timestamp ok')
# 2. HMAC berechnen
payload = str(request['headers']['callback-timestamp']) + '.' + request['body']
expected_hmac = hmac.digest(CALLBACK_SECRET.encode("utf-8"), payload.encode("utf-8"), digest=sha512)
expected_hmac_hex = binascii.hexlify(expected_hmac).decode('utf-8')
print('hmac', expected_hmac_hex)
# 3. Berechneten HMAC mit HMAC aus HTTP-Header vergleichen
if not hmac.compare_digest(request['headers']['callback-authentication'], expected_hmac_hex):
print('Error: invalid hmac')
sys.exit(2)
else:
print('hmac ok')
Das vollständige Script findet sich auch zur freien Verwendung im FIT-Connect-Tools-Repository.