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-Übersicht
Es werden Callbacks sowohl an einreichende, als auch an empfangende Systeme versendet. Hier gilt grundsätzlich, dass ein System über alle Veränderungen an einer Einreichung oder Rückantwort informiert werden, die es nicht selbst vorgenommen hat. Sobald eine Einreichung an den Zustelldienst übergeben wurde, wird das einreichende System über Zustandsänderungen informiert. Das empfangende System erhält hingegen nur einen Callback über die Einreichung, sofern dieser konfiguriert wurde.
Der Zustelldienst führt automatisiert Veränderungen an Einreichungen und Rückantworten durch, sobald Limits zur automatischen Löschung oder Ablehnung überschritten wurden. In diesem Fall müssen sowohl die einreichende Seite, als auch die empfangende Seite informiert werden.
Ereignis | Auslöser | Callback an einreichendes System | Callback an empfangendes System | Callback-Typ |
---|---|---|---|---|
create-submission | Einreichendes System | nein | nein | - |
submit-submission | Einreichendes System | nein | ja | NEW_SUBMISSIONS |
notify-submission | Zustelldienst | ja | nein | NEW_EVENTS |
forward-submission | Empfangendes System | ja | nein | NEW_EVENTS |
reject-submission | Empfangendes System | ja | nein | NEW_EVENTS |
reject-submission | Zustelldienst | ja | ja | NEW_EVENTS |
accept-submission | Empfangendes System | ja | nein | NEW_EVENTS |
delete-submission | Zustelldienst | ja | ja | NEW_EVENTS |
create-reply | Einreichendes System | nein | nein | - |
submit-reply | Einreichendes System | nein | ja | NEW_REPLIES |
reject-reply | Zustelldienst | ja | ja | NEW_EVENTS |
reject-reply | Empfangendes System | ja | nein | NEW_EVENTS |
accept-reply | Empfangendes System | ja | nein | NEW_EVENTS |
delete-reply | Zustelldienst | ja | ja | NEW_EVENTS |
notify-reply | Zustelldienst | ja | nein | NEW_EVENTS |
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 /v1/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
Konfiguration von Callbacks für Onlinedienste
Bei der Erstellung von Einreichungen über die Submission-API (POST /v1/submissions
) kann ebenfalls ein Callback konfiguriert werden.
Hierbei muss ebenfalls ein Callback-Objekt mit url
und secret
übergeben werden, damit der Zustelldienst über neue Ereignisse informieren kann.
Die Callback-Adresse muss für jede Adresse neu gesetzt werden und stellt einen optionalen Parameter dar.
Alternativ können die Events über die Submission-API unter Angabe der Case-ID unter GET /v1/cases/{caseId}/events
oder mit der Submission-ID unter GET /v1/submissions/{submissionId}/events
abgefragt werden.
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.
Wiederholung von Callbacks
Falls Callbacks nicht erfolgreich zugestellt werden können, gibt es im Zustelldienst Retry-Mechanismen, die weitere Zustellversuche durchführen. Hierbei werden über einen Backoff-Mechanismus die Callback-Nachrichten erneut an die hinterlegte Adresse gesendet. Es wird bis zu 14 Tage versucht den Callback beim zu informierenden System zuzustellen.
Eine Ausnahme bildet der Callback für submit-submission
Events.
Hier wird im Fehlerfall die Zustellung des Callbacks so lange versucht, bis die Einreichung sich nicht mehr im Zustand SUBMITTED
befindet.
Das kann durch die Annahme oder Ablehnung durch das empfangende System oder durch die automatische Ablehnung durch den Zustelldienst erfolgen.
Hier finden Sie weitere Informationen zu Benachrichtigungen und Löschfristen.