Token-Invalidierung in verteilten Systemen
Auf dieser Seite
Schnelle Systeme zu bauen ist knifflig, und verteiltes Rechnen ist oft der Weg, um die Performance zu verbessern. Das bringt eigene Herausforderungen für die Sicherheit mit sich, vor allem bei Authentifizierung und Autorisierung. Die JSON Web Tokens von OAuth 2 lösen das, schaffen aber ein Risiko beim Widerruf.
Verteilte Authentifizierung bei SEEK
SEEK kennt das Modell des verteilten Rechnens gut. Fast alles, worauf du zugreifst, kommt von Dutzenden Microservices, die in unterschiedlichen Sprachen geschrieben sind und von verschiedenen Teams betreut werden.
Sidecar: eine in sich geschlossene Aufgabe, die an die Hauptanwendung angehängt ist, meist in einem eigenen Prozess oder Container, und die Services unabhängig von der Sprache eine einheitliche Schnittstelle bietet.
Bei SEEK haben wir das gelöst, indem wir neben unseren Anwendungen einen Sidecar eingeführt haben. Der Sidecar validiert Tokens, nimmt eingehende Requests an oder lehnt sie ab und reicht den Kontext des Nutzers an die Anwendung weiter.
Damit die vielen Sprachen bei SEEK bedient werden, haben wir HTTP als einheitliche Schnittstelle gewählt. Es gibt in fast allen unseren Sprachen eine Implementierung, und Header eignen sich gut, um Requests um zusätzliche Informationen zu ergänzen.
Du kannst den Authentication Sidecar auch als Proxy sehen.
Ein Beispiel für das Sidecar-Entwurfsmuster mit zwei Task-Sets in einer Cloud-Umgebung mit Autoscaling. Du siehst, wie ein erfolgreicher Request durch den Sidecar an den Application-Task weitergereicht wird und ein nicht autorisierter Request am Sidecar endet. Hier nutzt der Authentication Sidecar ein gecachtes JSON Web Key Set (JWKS), um die Signatur der Tokens zu prüfen. So lassen sich Tokens verteilt validieren, ohne bei jedem Request den Identity Provider anzufragen.
Dieses Modell ist schnell und skalierbar, bringt aber ein Risiko mit: Ein gesperrter Nutzer kann bis zum Ablauf seines JSON Web Tokens (JWT) weiter Requests senden. Die Spezifikation empfiehlt keine Ablaufzeit, aber üblich sind kurze Laufzeiten von etwa 15 Minuten.
Token-Widerruf
Zum OAuth-2-Standard gehört RFC7009, die Spezifikation für den Token-Widerruf. Sie beschreibt den recht simplen Ablauf, mit dem Tokens widerrufen werden.
Die Spezifikation sieht einen Endpunkt vor, den ein Client aufrufen kann, um das Token zu übermitteln, das er widerrufen will. Spätere Validierungsanfragen werden dann abgelehnt, weil das Token nun als ungültig gilt.
Diese Spezifikation funktioniert nur mit opaken Tokens, nicht mit JSON Web Tokens. Die Herausforderung gibt es in vielen Unternehmen, auch bei SEEK. Unsere verteilte Architektur macht es extrem schwer, Tokens effizient gegen eine zentrale Quelle zu prüfen. Deshalb signieren wir Tokens mit kurzer Laufzeit und nehmen das Risiko in Kauf, dass ein gesperrter Nutzer bis zum Ablauf des Tokens weiter Requests stellen kann.
Eine weitere Herausforderung ist ein Mechanismus, um das Token zuzuordnen. JSON Web Tokens enthalten alle Informationen, die nötig sind, um den Nutzer zu identifizieren. Sie werden gepackt, signiert und verschickt, nicht gespeichert. Es braucht also einen zusätzlichen Claim, der das Token identifiziert. Dafür gibt es die JWT ID.
Verteilte Token-Invalidierung
Tokens in einem verteilten System zu invalidieren ist knifflig. Mit einem Bloom-Filter lässt sich aber der Aufwand deutlich senken, widerrufene JWT IDs gegen eine zentrale Quelle zu prüfen.
Tokens sind in der Regel kurzlebig, und wir würden in keinem Szenario erwarten, 100.000.000 Tokens sperren zu müssen. Die passen als Bloom-Filter locker in etwa 500 MB Speicher, bei einer Chance von 1 zu 999.925.224 auf ein falsch positives Ergebnis.
Für dieses Szenario arbeite ich an oauth-revokerd. Der Service führt eine Liste widerrufener JWT IDs und verteilt dazu einen passenden Bloom-Filter.
Der Service bietet eine In-Memory-Datenbank, die widerrufene Tokens kurzfristig vorhält, bis zum Ablauf des Tokens selbst. Die Idee: Der Service soll sich schnell und mit minimaler Konfiguration hochfahren lassen, eine Management-API zum Widerrufen von Tokens bieten und eine Query-API, um Widerrufe bei falsch positiven Treffern zu verifizieren.
In diesem Konzept wird der Sidecar erweitert, damit er den Bloom-Filter nutzt.
Fazit
Das war’s erst mal. Ich hoffe, mit dem Projekt in Zukunft mehr zu machen, und poste Updates zum Stand auf meiner Website.