Zum Hauptinhalt springen

Analyse von Risiken durch eine fehlerhafte Nutzerauthentifizierung bei JSON Web Token

Nitzan Namer

Verfasser

Nitzan Namer

June 07, 2023

Nitzan Namer

Verfasser

Nitzan Namer

Nitzan Namer is a Security Researcher at Akamai.

Kontoübernahme, Berechtigungseskalation und Datenlecks sind drei große potenzielle Risiken, denen JWT‑Nutzer und Unternehmen ausgesetzt sind, wenn sie ein JWT als bevorzugtes Token in einer API auswählen.

Zusammenfassung

  • Forscher von Akamai haben JSON Web Token (JWTs) als Angriffsvektor für eine fehlerhafte Nutzerauthentifizierung untersucht, die in den Top 10 der API‑Sicherheitsrisiken des Open Web Application Security Project (OWASP) aufgeführt sind. Dabei hat das Team verschiedene Szenarien ermittelt, in denen JWT‑Bedrohungen und -Trends auftreten. 

  • JWTs sind für den Schutz von APIs verantwortlich, denn Sie stellen Token (in der Regel zwischen Clients und Servern) zur sicheren Verifizierung von Nutzern aus. Diese Token sind eines der am häufigsten verwendeten Verifizierungsformate und enthalten Informationen, die in Form von JSON‑Objekten geteilt werden.  

  • Obwohl nicht jedes Token verschlüsselt ist, ist es codiert und trägt eine Verifizierungssignatur. Wir haben einige der vielen JWT‑Risiken untersucht, die auf unsachgemäße Umsetzung oder geringe Entropie und kurze Geheimschlüssel zurückzuführen sind.  

  • Kontoübernahme, Berechtigungseskalation und Datenlecks sind drei große potenzielle Risiken, denen JWT‑Nutzer und Unternehmen ausgesetzt sind, wenn sie ein JWT als bevorzugtes Token in einer API auswählen. Wir haben in unserem Traffic beobachtet, dass die meisten JWTs einen symmetrischen Algorithmus verwenden, obwohl dieser theoretisch weniger sicher ist.

  • In diesem Beitrag zeigen wir Best Practices für den Umgang mit diesen JWT‑Risiken auf.

Einführung

JWTs sind ein weit verbreitetes, relativ einfach zu implementierendes Tokenschema, das viele Risiken birgt. Diese Risiken müssen bei der Umsetzung und Sicherung von JWTs berücksichtigt werden. Eines der wichtigsten Risiken für JWTs, das in der OWASP API Security Top 10 aufgeführt ist, ist eine fehlerhafte Nutzerauthentifizierung. 

Eine fehlerhafte Nutzerauthentifizierung tritt auf, wenn eine API die Zugangsdaten und die Identität des Nutzers, von dem die Anfrage stammt, nicht richtig überprüft. Leider handelt es sich hierbei um eine häufig bei JWTs beobachtete Schwachstelle. Diese kann dazu führen, dass ein Angreifer das Konto eines anderen Nutzers nachahmt oder darauf zugreift, was zu einer Berechtigungseskalation und zu Datenlecks führen kann.

Schutz der Pipeline

Ein JWT ist ein Authentifizierungstoken, das häufig in APIs und Webanwendungen verwendet wird. Wir haben in unserem Traffic beobachtet, dass Webanwendungen mehr APIs verwenden und sie Kunden zugänglich machen, wodurch die Notwendigkeit einer nahtlosen Authentifizierung an verschiedenen API‑Endpoints zunimmt. 

Die API ist die wichtigste Pipeline eines Unternehmens, die die Authentifizierungs- und Autorisierungsmechanismen enthält, Datenbanken abfragt und den Zugang zu den meisten Funktionen des Unternehmens bereitstellt. Aus diesem Grund sind JWT‑Risiken im API‑Bereich besonders gefährlich. In diesem Blogbeitrag stellen wir die Grundlagen von JWTs, sechs Risiken für JWTs sowie Möglichkeiten vor, diese Risiken zu minimieren.

Die Grundlagen von JWTs

JWT ist ein Format zum Senden signierter JSON‑Daten, um Daten an Webanwendungen, mobile Apps und APIs zu übertragen, die meist nur zur Authentifizierung verwendet werden. Die JWT‑Struktur besteht aus drei Elementen: dem Header (auch als JOSE‑Header bezeichnet), der Payload und der Signatur, die jeweils durch einen Punkt getrennt sind (Abbildung 1).

  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIiLCJpYXQiOjE2NzYyMTc5NTAsImV4cCI6MTcwNzc1Mzk1MCwiYXVkIjoiYWthbWFpLWJsb2ciLCJzdWIiOiIiLCJjb21wYW55IjoiQWthbWFpIiwidXNlciI6IkFrYW1haS1yZWFkZXIiLCJhZG1pbiI6Im5vIn0.kMPz3Z7BSlBTJKijD8bcrpzTZejX7VCZ77w5oQwJO6I

Abb. 1: Beispiel für die drei Elemente der JWT‑Struktur

Header und Payload

Sowohl der Header als auch die Payload sind gemäß den IETF‑Empfehlungen in Base64 codiert, das für die Verwendung in URLs geeignet ist (Abbildung 2). „Codiert“ bedeutet, dass sie nicht direkt mit bloßem Auge lesbar sind, vom Server jedoch leicht decodiert werden können. Damit sollen die Integrität und Usability der Daten und gleichzeitig die URL‑Sicherheit gewährleistet werden. Auf diese Weise gibt es keine sich überlappenden Zeichen, die von Webbrowsern verwendet werden.

Der JOSE‑Header wird sowohl für das JWT als auch für die JSON‑Webverschlüsselung (JSON Web Encryption, JWE) verwendet, bei der es sich im Grunde um ein verschlüsseltes JWT handelt, durch das die häufigsten JWT‑Angriffe abgewehrt werden. Das Feld, das die gewählte Tokenmethode angibt, heißt „typ“ (typ:JWT/JWE). Die Payload kann je nach Implementierung registrierte Felder (die von der Internet Assigned Numbers Authority angefordert werden) oder nutzerdefinierte Felder enthalten.

Der JOSE-Header wird sowohl für JWT als auch für JSON Web Encryption (JWE) verwendet

Abb. 2: Codiertes JWT

Signatur

Der Zweck der Signatur besteht darin, das Token zu verifizieren. Sie bedeutet, dass der Server das Token erstellt hat und sich die Daten seit der Erstellung nicht geändert haben.

Beim Erstellen der Signatur gibt es zwei wesentliche Schritte:

  1. Die Anwendung eines Verschlüsselungsalgorithmus (z. B. MAC) auf den Header und die Payload, die durch einen Punkt getrennt sind (der Algorithmus verwendet einen Geheimschlüssel)

  2. Die Anwendung eines Hashing-Algorithmus (z. B. SHA256) auf den verschlüsselten Header und die verschlüsselte Payload

Wenn ein JWT verwendet wird, überprüft der Server die Signatur, um das Token selbst zu validieren. (Später in diesem Beitrag erläutere ich die verschiedenen Algorithmen, die zur Validierung verwendet werden.)

JWTs werden in Webanwendungen häufig zur Authentifizierung eingesetzt, da sie (auch in großem Umfang) nutzerfreundlich und einfach zu implementieren sind und weil die erforderlichen Daten des Servers clientseitig gespeichert werden. Doch obwohl sie eine Signatur tragen, gibt es Risiken im Zusammenhang mit JWT. Das JWT verwendet Klartext und jede Implementierung besteht aus verschiedenen Payload-Feldern. Die entsprechende Angriffsfläche ist also sehr groß und es gibt viel Raum für Fehler.

Durch die Untersuchung einiger der häufigeren und interessanteren Bedrohungen, denen JWTs ausgesetzt sind, können wir Schwachstellen und schädliches Verhalten leichter erkennen, Risiken besser reduzierten und die notwendigen Sicherheitsmaßnahmen vorbereiten, um uns vor potenziellen Angriffen zu schützen. 

Es ist unser Ziel, Nutzern einen sichereren Ansatz bei der Arbeit mit JWTs zu bieten und Sicherheitsexperten und Administratoren die Tools und Empfehlungen zur Verfügung zu stellen, die sie benötigen. 

Sechs Risiken für JWTs

1. Der Server darf ein Token ohne Validierung verwenden

Da ein JWT eine Signatur trägt und nicht verschlüsselt ist, muss es vor der Verwendung validiert werden. Im einfachsten Bedrohungsszenario, bei dem eine Anwendung keine Validierung durchführt, kann ein Angreifer den Dateninhalt manipulieren (z. B. um Berechtigungen zu erhöhen) und die Signatur unverändert lassen oder sie sogar löschen, um höhere Berechtigungen zu erlangen.

Eine weitere Methode ist die Verwendung des Parameters „alg“ im Header, der den Algorithmus darstellt, der zum Signieren des Tokens verwendet wurde. „None“ ist ein legitimer Wert (und das JWT wird als „ungesichertes JWT“ bezeichnet), sodass jeder das Token problemlos signieren kann. Am Backend gibt es ebenfalls eine mögliche Implementierung der JWT‑Verifizierung.

Suchen Sie zunächst nach dem Feld „alg“ im Header. Verwenden Sie danach den angegebenen Algorithmus, um das Token zu verifizieren. Der Algorithmus „None“ bedeutet, dass für dieses Token keine Signatur und Verifizierung erforderlich ist. Die Bearbeitung der Payload und des Headers (zu „alg:none“) und die „Selbstsignierung“ (Löschen der Signatur) des Tokens führt zu einem erfolgreichen Angriff.

Beispiel

Abbildung 3 zeigt ein Beispiel für ein decodiertes JWT.

  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZXhhbXBsZSBuYW1lIiwiaWF0Ij 
  oxNjU5MjM5MDIyfQ.PrhAp2DUWXoL01_odyLATuzrwn5rMtY1IVsP8y4LH5E
  decoded:
{
  "alg": "HS256",
  "typ": "JWT"
}
.{
  "name": "example name",
  "iat": 1659239022
}

Abb. 3: Beispiel für ein decodiertes JWT

Wir gehen davon aus, dass der API‑Endpoint das Feld „alg“ in der Payload als den für die Validierung gewählten Algorithmus verwendet.

Wir möchten jedoch das JWT bearbeiten (Abbildung 4). Auf diese Weise gelingt es uns, ein gültiges JWT eines anderen Nutzers zu erstellen.

  eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiZXhhbXBsZSBuYW1lIiwiaWF0Ijo 
  xNjU5MjM5MDIyfQ.
  decoded:
{
  "alg": "none",
  "typ": "JWT"
}
.{
  "name": "other person's name",
  "iat": 1659239022
}

Abb. 4: Bearbeitetes JWT zur Ausnutzung von alg:none

Best Practice: Es ist ganz einfach: Führen Sie immer eine Validierung mit einem festcodierten, vordefinierten Algorithmus durch, bevor Sie das Token verwenden. Verwenden Sie den alg-Parameter nicht als Zeiger für den Validierungsalgorithmus.

2. Verwendung desselben privaten Schlüssels für verschiedene Anwendungen

Es gibt viele Unternehmen, die eine separate Anmeldung für verschiedene Anwendungen verwenden. Wenn Sie denselben privaten Schlüssel verwenden, wird in beiden Anwendungen ein gültiges Token erstellt, jedoch jeweils mit einer anderen Nutzer‑ID. In diesem Fall können Angreifer eine Anfrage an eine zweite Anwendung senden und dabei das Token der ersten Anwendung verwenden, um ein Konto zu übernehmen (das nicht frei wählbar ist) (Abbildung 5).

Screenshot: Verwendung des JWT einer zweiten Anwendung Abb. 5: Verwendung des JWT einer zweiten Anwendung in einer anderen Anwendung, was zu einer Kontoübernahme führt

Best Practice: Eine weitere einfache Faustregel lautet: Verwenden Sie beim Trennen von Nutzer‑IDs unterschiedliche private Schlüssel.

 3. Verwendung eines schwachen Signieralgorithmus

Es gibt zwei Hauptgruppen von Algorithmen: symmetrische (HSXXX) und asymmetrische (RSXXX, ESXXX, PSXXX). Ein symmetrischer Algorithmus erfordert einen gemeinsamen Geheimschlüssel; ein asymmetrischer Algorithmus erfordert private und öffentliche Schlüssel (Tabelle 1).

Symmetrisch

HSXXX

HMAC + SHA

Relativ schwacher Algorithmus

Verwendet einen gemeinsamen Geheimschlüssel

Asymmetrisch

RSXXX

RSA + SHA

Sicherer Algorithmus

Verwendet private und öffentliche Schlüssel

ESXXX

ECDSA + SHA

Der sicherste Algorithmus der drei

Verwendet private und öffentliche Schlüssel

Tabelle 1: Die beiden wichtigsten Gruppen von Algorithmen

Aus Perspektive des Angreifers lässt sich ein symmetrischer Algorithmus einfacher durch einen Brute‑Force-Angriff ausnutzen, denn es ist nicht erforderlich, öffentliche Schlüssel zu sammeln, und die Berechnungszeit ist so effizient wie möglich. Wir haben in unserem Traffic beobachtet, dass symmetrische Algorithmen häufiger verwendet werden als asymmetrische Algorithmen (Abbildung 6).

Theoretisch erfordern symmetrische Algorithmen weniger Berechnungen, sodass sie in großem Maßstab eine bessere Performance als asymmetrische Algorithmen bieten.

Screenshot: Umfrage zu JWT-Algorithmen Abb. 6: Eine Umfrage zu JWT-Algorithmen im Traffic von Akamai zeigt, dass symmetrische Algorithmen am häufigsten verwendet werden

Best Practice: Verwenden Sie asymmetrische Algorithmen. Wir empfehlen die Verwendung des ECDSA‑Algorithmus, der derzeit (aus kryptografischer Sicht) die sicherste Wahl ist. Ein ordnungsgemäß gesicherter symmetrischer Schlüssel ist akzeptabel, wenn der Geheimschlüssel eine hohe Entropie aufweist und ausreichend lang ist.

4. Auswahl eines privaten Schlüssels, der kurz ist und/oder eine geringe Entropie aufweist

Ein privater Schlüssel, der kurz ist und/oder eine geringe Entropie aufweist, könnte schnell mithilfe eines Brute‑Force-Angriffs geknackt werden. Es gibt eine simple Software zum Knacken von Schlüsseln, die in leistungsstarken Cloudumgebungen mit Graphic Processing Units (GPU) installiert werden kann. Die GPU‑Performance wächst rapide und beeinflusst Funktionen zum Knacken von Schlüsseln. Moderne High‑End-Grafikkarten knacken einen Schlüssel fast 2,5‑mal schneller als noch vor drei Jahren. 

In Tabelle 2 sehen Sie einen Vergleich, wie viele Tage es vor drei Jahren dauerte und wie viele es heute dauern würde, einen achtstelligen privaten Schlüssel zu knacken (unabhängig von seiner Entropie).

High‑End-Grafikkarte


Tage bis zum Knacken des Schlüssels

Vor drei Jahren

10,5 Tage

Heute

4,5 Tage

Tabelle 2: Anzahl der Tage bis zum Knacken eines achtstelligen privaten Schlüssels

Ein siebenstelliger privater Schlüssel, der vor ein paar Jahren in etwa 24 Stunden geknackt worden wäre, kann heute in weniger als 90 Minuten geknackt werden. Der Einzigartigkeit dieses Angriffs liegt darin, dass er offline ausgeführt wird, ohne dass eine Abwehr seitens des Unternehmens möglich ist oder überhaupt jemand bemerkt, dass ein solcher Angriff stattfindet. 

Stellen Sie sich vor, Sie sind ein Angreifer, der von einer Regierung beauftragt wird und dafür ein Orchestrierungssystem erstellt. Wenn der Angreifer den privaten Schlüssel des JWT kennt, kann er ein signiertes Token erstellen und sich als ein anderer Nutzer ausgeben, allein wenn er dessen ID kennt.

Best Practice: Wählen Sie einen langen privaten Schlüssel (mindestens 10 Zeichen) mit hoher Entropie. Wir empfehlen die Verwendung von RSA zum Generieren von Geheimschlüsseln.

5. Sensible Daten in der Payload eines JWT

JWTs sind Base64-URL-codiert, d. h., die Payload ist nicht verschlüsselt. Das Speichern von DB‑Namen, inkrementellen IDs (aller Art) oder beliebigen internen Feldern und Daten eines Servers führt zu einer übermäßigen Datenoffenlegung, die Angreifer für andere Angriffsvektoren ausnutzen können (z. B. fehlerhafte Autorisierung auf Objektebene).

Best Practice: Speichern Sie keine sensiblen Daten in einem JWT. Wenn Sie sensible Daten speichern müssen, verwenden Sie JWE.

6. Verwechslung von Schlüsseln

Bei asymmetrischen Algorithmen wird ein privater Schlüssel verwendet, um das JWT (also seine Signatur) zu fälschen. Zur Validierung des JWT wird ein öffentlicher Schlüssel verwendet. Ein Angreifer kann den im Header angegebenen Algorithmus in einen symmetrischen Algorithmus (z. B. HS256) umwandeln und mit dem öffentlichen Schlüssel, den der Server ordnungsgemäß zur Verifizierung verwendet, eine Signatur erstellen. 

In diesem Szenario verwendet das nicht ordnungsgemäß implementierte Backend den öffentlichen Schlüssel und führt den symmetrischen Algorithmus (wie vom Angreifer im Header angegeben) aus, um das vom Angreifer erstellte JWT erfolgreich zu validieren.

Beispiel

Abbildung 7 zeigt, wie der Server ein neues JWT erstellt, und Abbildung 8 veranschaulicht den Prozess der JWT‑Validierung des Servers.

Abbildung 7 zeigt den Prozess des Servers zur Erstellung eines neuen JWT Abb. 7: Serverseitige JWT-Erstellung
Abbildung 8 zeigt den JWT-Validierungsprozess eines Servers Abb. 8: Serverseitige JWT-Validierung

Im letzten Teil der Validierung kann aus einem von zwei Gründen (oder aus beiden) ein Fehler im Vergleich auftreten: 

  1. Header und Payload wurden bearbeitet, die Signatur jedoch nicht. 

  2. Es gibt eine Fehlkonfiguration des richtigen Algorithmus oder des richtigen Schlüssels.

Abbildung 9 zeigt einen Angriff mit Verwechslung der Schlüssel.

JWT-Fälschungsprozess Abb. 9: JWT-Fälschungsprozess eines Angreifers mit Verwechslung von Schlüsseln

Der letzte Schritt: Der Server überprüft das Token mit dem in Abbildung 8 dargestellten Prozess, in dem der Server dem alg‑Feld vertraut. Er überprüft das Token, indem er den HS256‑Algorithmus mit dem öffentlichen Schlüssel als Geheimschlüssel ausführt, was genau dem Plan des Angreifers entspricht.

Best Practice: Verwenden Sie vordefinierte Algorithmen zur Validierung und vertrauen Sie nie Nutzereingaben.

Fazit

JWT ist das am häufigsten verwendete Authentifizierungstoken. Es ermöglicht die Verwendung vieler Webanwendungen und APIs während der Authentifizierung, ohne sich regelmäßig anmelden zu müssen. Es gibt jedoch viele Risiken im Zusammenhang mit JWTs, da sie weder verschlüsselt sind, noch sicher implementiert werden. 

  • Die Rechenleistung entwickelt sich rasant, wodurch schwache Geheimschlüssel einem großen Risiko ausgesetzt sind, da sie innerhalb von Tagen (statt ehemals Jahren) geknackt werden können. Im Falle von JWTs kann diese Art von Angriff offline ausgeführt werden, ohne dass ein Unternehmen es überhaupt bemerkt. 

  • Symmetrische Algorithmen sind die häufigste Art von Algorithmen, was es Angreifern umso leichter macht. 

  • Es gibt auch komplexere Bedrohungen, wie z. B. Authentifizierungsangriffe – aber diese Authentifizierungsangriffe automatisiert durchzuführen, ist für Angreifer schwierig. Einfache JWT‑Angriffsvektoren können jedoch automatisiert und massiv ausgenutzt werden.

Aus diesen (und vielen anderen) Gründen ist es entscheidend, dass sich Nutzer der JWT‑Schwachstellen und Sicherheits-Best‑Practices bewusst sind, die zum Schutz vor potenziellen Angriffen implementiert werden müssen. Wir hoffen, dass diese Analyse Ihnen als praktischer Leitfaden zum Schutz von JWTs vor fehlerhafter Nutzerauthentifizierung dient, einer der zehn größten API‑Schwachstellen laut OWASP.



Nitzan Namer

Verfasser

Nitzan Namer

June 07, 2023

Nitzan Namer

Verfasser

Nitzan Namer

Nitzan Namer is a Security Researcher at Akamai.