Hinweise für die Authentifizierung von WebHooks mit Hilfe von JWT, OAuth (mit JWT) und OIDC (Connect 2024)
Da unsere Kunden immer wieder eine Authentifizierung mittels OAuth anfordern, haben wir uns dazu entschlossen dieses Szenario zu unterstützen. Dennoch möchten wir an dieser Stelle klar auf folgenden Sachverhalt hinweisen: OAuth wurde nicht zur Authentifizierung von Benutzern oder Personen entwickelt, sondern ist ein Framework für die sogenannte “delegierte Autorisierung”, d. h. OAuth erlaubt es Benutzern, ihre privaten Ressourcen auf einer Website mit einer anderen Website zu teilen, ohne dabei ihre Anmeldeinformationen teilen zu müssen. Für die Authentifizierung von Benutzer wurde das von Connect ebenfalls unterstützte Verfahren OpenID Connect (OIDC) entwickelt.
Allgemeine Informationen zu Funktionsweise
Aus sicht des Aufgerufenen Systems wird bei der empfangenen HTTP-Anforderung als Authentifizierungsinformation ein sogenanntes JSON Web Token (JWT) mitgesendet. Eine Beschreibung des genauen Aufbaus eines JWTs ist in RFC7519 beschrieben. Die Aufgabe des Empfängers (also von Connect) ist es, das Token zu dekodieren und auf Gültigkeit zu überprüfen. Hierbei stellt die Überprüfung der Gültigkeit der Signatur des Ausstellers den wichtigsten Teil der Überprüfung dar. Hierfür müssen die öffentlichen Schlüssel aller als zulässig zu betrachtenden Herausgebers von JWTs bei Connect bekanntgegeben werden. Die kann durch drei unterschiedliche Mechanismen geschehen, welche bei Bedarf auch kombiniert werden können:
Direkte Angabe der Schlüssel als JSON Web Key Set (JWKS)
Angabe einer URI, unter der die aktuelle gültigen Schlüssel als JSON Web Key Set (JWKS) bezogen werden können
Ermittlung der URI unter der die aktuelle gültigen Schlüssel als JSON Web Key Set (JWKS) bezogen werden können mittels OIDC Discovery (nur OIDC)
Hierbei ist zu beachten, dass der Herausgeber der JWTs die verwendeten Schlüssel meist in einem regelmäßigen Zeitintervall ändert (Automatic Key Rollover). Aus diesem Grund sollten die Methoden 2 und 3 bevorzugt werden, da Connect hierbei automatisch auf Änderungen der Signaturschlüssel reagieren kann. Die erste Variante findet meist bei kundeneigenen Entwicklungen Verwendung, welche keinen Automatic key Rollover unterstützen.
Nachdem die Gültigkeit sie Signatur überprüft wurde, sollten folgende Prüfungen durchgeführt werden:
Liegt die aktuelle Systemzeit innerhalb des Gültigkeitszeitraums des JWTs? Ist die nicht der Fall, ist das Token als abgelaufen und somit als ungültig zu betrachten.
Ist das JWT für die Authentifizierung beim Connect Server bestimmt? Bei der Erstellung des Tokens trägt der Herausgeber den Namen des Empfängers in das Feld “Audience” ein. Enthält dieses Feld beim empfangenen Token nicht den erwarteten Wert, so wurde es zu einem anderen Zweck als zur Authentifizierung beim Connect Server ausgestellt und somit als ungültig betrachtet,
Optional kann der im JWT vermerkten Herausgeber mit den Werten in einer Liste von zulässigen Herausgebern verglichen werden. Wird dieser dort nicht gefunden, so wird das Token als ungültig betrachtet. Solange sichergestellt ist, dass der zur Signatur verwendeten Schlüssel nur den zulässigen Herausgebern bekannt ist, kann diese Prüfung entfallen. In Umgebungen wie z. B. Azure AD, bei denen der Herausgeber für mehrere Tenants zuständig ist und für alle Tenants dieselben Signaturschlüssel verwendet, kann diese Prüfung sicherstellen, dass das Zugriffstoken nicht ursprünglich für einen anderen Tenant bestimmt war.
Optional kann der verwendete Signaturalgorithmus mit den Werten in einer Liste von zulässigen Signaturalgorithmen verglichen werden. Wird dieser dort nicht gefunden, so wird das Token als ungültig betrachtet. Diese Prüfung erlaubt es, die Verwendung von nicht erwünschten Signaturalgorithmen zu unterbinden.
Optional kann die Actor-Token-Validierung aktiviert werden. Ein JWT enthält in der Regel ein Feld namens “sub” (Subject), welches den Benutzer identifiziert, für den das Token ausgestellt wurde. Ein zusätzliches optionales Feld namens “actor” enthält ein weiteres JWT und identifiziert den Benutzer, der im Namen des Subjekts handelt. Bei der Actor-Token-Validierung wird auch dieses Token gemäß der konfigurierten Prüfungsoptionen validiert (ggf. auch rekursiv).
Konfiguration der JWT-Authentifizierung für Webhook-Aufrufe eines bestimmten Services
Zu Aktivierung der Authentifizierung über ein JWT, muss in der Servicedefinition des entsprechenden Services der Server Handler “HttpOAuthHandler“ eingetragen werden. Aus Performancegründen empfiehlt es sich, diesen stets als ersten Server Handler einzutragen. Dadurch werden ungültige HTTP-Anforderungen bereits vor einer inhaltlichen Bearbeitung durch den Connect Server direkt abgewiesen.
Die entsprechende Server Definition sieht dann z. B. folgendermaßen aus:
Das Objekt mit dem Namen “$params” enthält die Eigenschaften zur Konfiguration der Authentifizierung. Derzeit werden folgende Eigenschaften unterstützt:
Eigenschaftsname | Type | Standardwert | Beschreibung |
---|---|---|---|
AllowNonce | boolean | true | In einem JWT kann ein Nonce-Wert dazu verwendet werden, eine Client-Sitzung mit einem ID-Token zu verknüpfen. Wird bei der Verwendung von Azure AD ein Zugriffstoken über OIDC angefordert und hierbei ein Scope verwendet, welcher auch für Abfragen über Microsoft Graph gedacht ist, so wird im JWT eine Zeichenkette als Nonce-Wert eingetragen. Die aktuelle Implementierung der JWT-Validierung des .NET-Frameworks erwartet an dieser Stelle jedoch den SHA256-Hash dieser Zeichenkette und klassifiziert die Signatur des JWTs somit als ungültig. Wir die Eigenschaft “AllowNonce“ auf den Wert true gesetzt, aktiviert dies eine vorgelagerte Anpassung betreffender JWTs, so dass eine Validierung durch das .NET-Framework möglich ist. |
AuthorizationProvider | string | ““ | Wird für die Erzeugung des JWT ein Dienst benutzt, welcher OIDC-Discovery unterstützt und beim Connect Server als Autorisierungsprovider konfiguriert ist, so kann hier der Name des entsprechenden Autorisierungsprovider eingetragen werden. Dadurch werden die gültigen Signaturschlüssel automatisch anhand der über OIDC-Discovery bereitgestellten Informationen bezogen und auch Key-Rollovers automatisch bei der Validierung berücksichtigt. |
ClockSkew | TimeSpan | TimeSpan.Zero | Mit diesem Parameter kann die Toleranz-Zeitspanne für die Überprüfung des Gültigkeitszeitraums eines JWTs definiert werden. Dies ermöglicht die Kompensation von abweichenden Systemzeiten. Aus Sicherheitsgründen empfehlen wir dringend, diesen Parameter nicht zu verwenden und stattdessen für eine funktionierende Synchronisation der Systemzeiten zu sorgen. |
JwksData | string | ““ | Spezifiziert die gültigen Signaturschlüssel als JWKS. Bitte beachten Sie, dass das JWKS nach einem Key-Rollover manuell angepasst werden muss. Aus diesem Grund sollte der Bezug der Signaturschlüssel über eine URI oder über OIDC-Discovery bevorzugt werden. |
JwksUri | string | ““ | Spezifiziert eine URI für den Bezug der gültigen Signaturschlüssel als JWKS. Werden bei einem Key-Rollover die neuen Schlüssel direkt publiziert, wird diese Änderung bei der Validierung automatisch berücksichtigt. |
ProxyUri | string | ““ | Soll für den Bezug der Signaturschlüssel über eine URI ein bestimmter Proxy-Server verwendet werden, kann hier die URI des Proxy-Server hinterlegt werden. |
ProxyUser | string | ““ | Soll für den Bezug der Signaturschlüssel über eine URI ein bestimmter Proxy-Server verwendet werden und erfordert diese eine Authentifizierung, kann hier der für die Authentifizierung verwendete Benutzername hinterlegt werden. |
ProxyPassword | string | ““ | Soll für den Bezug der Signaturschlüssel über eine URI ein bestimmter Proxy-Server verwendet werden und erfordert diese eine Authentifizierung, kann hier das für die Authentifizierung verwendete Passwort hinterlegt werden. |
ProxyDomain | string | ““ | Soll für den Bezug der Signaturschlüssel über eine URI ein bestimmter Proxy-Server verwendet werden und erfordert diese die Angabe einer Domäne, kann diese hier hinterlegt werden. |
RequireExpirationTime | boolean | true | Dieser Parameter gibt an, dass nur JWTs akzeptiert werden, welche einen Gültigkeitszeitraum enthalten. Wir empfehlen den Standardwert nicht zu verändern. |
RequireSignedTokens | boolean | true | Dieser Parameter gibt an, dass nur JWTs akzeptiert werden, welche vom Herausgeber digital signiert wurden. Wir empfehlen den Standardwert nicht zu verändern. |
ValidateActor | boolean | true | Aktiviert die Validierung des im JWT enthaltenen Actor-Tokens (ggf. auch rekursiv). Wir empfehlen den Standardwert nicht zu verändern. |
ValidateIssuerSigningKey | boolean | true | Aktiviert die Validierung des für die Signatur verwendeten Schlüssels. Wir empfehlen den Standardwert nicht zu verändern. |
ValidateLifetime | boolean | true | Aktiviert die Validierung des im JWT hinterlegten Gültigkeitszeitraums. Wir empfehlen den Standardwert nicht zu verändern. |
ValidAlgorithms | string[] | [] | Definiert eine Liste mit zulässigen Signaturalgorithmen und aktiviert die Validierung des Signaturalgorithmus. Diese Prüfung erlaubt es, die Verwendung von nicht erwünschten Signaturalgorithmen zu unterbinden. Eine Liste der möglichen Werte finden Sie hier: https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms. |
ValidAudience | string | ““ | Enthält den zu erwartenden im JWT hinterlegten Empfänger (Audience) und aktiviert gleichzeitig die Validierung des Empfängers. Dadurch kann die Verwendung gültiger Zugrifftokens, die für einen anderen Zweck ausgestellt wurden, unterbunden werden. |
ValidIssuers | string[] | [] | Definiert eine Liste mit zulässigen Herausgebern and aktiviert die Validierung des Herausgebers. In Umgebungen wie z. B. Azure AD, bei denen ein Herausgeber für mehrere Tenants zuständig ist und für alle Tenants dieselben Signaturschlüssel verwendet, kann diese Prüfung sicherstellen, dass das Zugriffstoken nicht ursprünglich für einen anderen Tenant bestimmt war. |