Skip to main content

Kann Snyk JWT-Sicherheitsprobleme erkennen?

Artikel von
blog feature ai green

4. März 2025

0 Min. Lesezeit

JWTs werden häufig von Entwicklerinnen und Entwicklern eingesetzt, die Authentifizierung anstelle herkömmlicher sitzungsbasierter Cookie-Verfahren implementieren möchten. Doch was passiert, wenn Entwicklerinnen und Entwickler die JWT-Sicherheit missverstehen und dadurch eine schwerwiegende Schwachstelle bei der Authentifizierung verursachen?

Was ist ein JWT?

JSON Web Tokens (JWTs) sind eine kompakte, eigenständige Möglichkeit, Informationen als JSON-Objekt sicher zwischen Parteien zu übertragen. Da sie digital signiert werden, häufig mithilfe von Zertifikaten, lassen sich diese Informationen überprüfen und als vertrauenswürdig einstufen. Für Webentwicklerinnen und -entwickler gehören JWTs zum Alltag, wenn sie ihren Anwendungen eine Authentifizierung hinzufügen und auf herkömmliche browserbasierte Cookie-Sicherheit und Sitzungsverwaltung verzichten möchten.

Aufbau eines JWTs

Wie oben beschrieben, ist ein JWT ein gewöhnliches JSON-Objekt, in dem Daten gespeichert werden. Ein JWT besteht aus einem Header, einer Payload und einer Signatur. Diese Komponenten werden in Base64 codiert und durch Punkte (.) miteinander verkettet, um den JWT-String zu bilden.

1. Header: Der Header besteht in der Regel aus zwei Teilen: dem Tokentyp JWT und dem verwendeten Signaturalgorithmus, zum Beispiel HMAC SHA256 oder RSA.

 {
     "alg": "HS256",
     "typ": "JWT"
   }

2. Payload: Die Payload enthält die Claims. Claims sind Aussagen über eine Entität (in der Regel den Benutzer) sowie zusätzliche Daten. Speichern Sie darin jedoch keine sensiblen oder vertraulichen Daten, da JWTs häufig nicht verschlüsselt sind und von jeder Person decodiert werden können, um auf die Daten zuzugreifen. Es gibt drei Arten von Claims: registrierte, öffentliche und private Claims.

{
     "sub": "1234567890",
     "name": "John Doe",
     "admin": true
   }

3. Signatur: Für die Signatur müssen Sie den codierten Header, die codierte Payload, ein Geheimnis und den im Header angegebenen Algorithmus verwenden und damit die Signatur erstellen.

 HMACSHA256(
     base64UrlEncode(header) + "." +
     base64UrlEncode(payload),
     secret)

Das resultierende JWT könnte so aussehen:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Die Rolle von JWTs in APIs und Microservices

JWTs spielen eine wichtige Rolle für Frontend- und Backend-Entwicklerinnen und -Entwickler, wenn sie Authentifizierung implementieren sowie APIs und Microservices entwickeln. Im Gegensatz zur herkömmlichen sitzungsbasierten Authentifizierung auf dem Server, bei der der Server einen dauerhaften Sitzungsstatus in einer Datenbank verwalten muss, ermöglichen JWTs dank ihrer Zustandslosigkeit einen skalierbareren und effizienteren Ansatz. Meldet sich ein Benutzer an, generiert der Server ein Token, das Benutzerinformationen codiert, und signiert es mit einem geheimen Schlüssel. Dieses Token wird anschließend an den Client gesendet, der es in den Header nachfolgender Anfragen einfügt.

Der Server kann die Signatur des Tokens überprüfen, um den Benutzer zu authentifizieren, ohne Sitzungsdaten zu speichern. Aufgrund ihrer Zustandslosigkeit eignen sich JWTs besonders gut für verteilte Systeme und Microservices-Architekturen, in denen ein zentraler Sitzungsspeicher zum Engpass oder Single Point of Failure werden könnte.

Beliebte Open-Source-JWT-npm-Pakete für Node.js

Für die Arbeit mit JWTs in Node.js steht Entwicklerinnen und Entwicklern eine Vielzahl von Open-Source-Bibliotheken zur Verfügung. Häufig entscheiden sie sich jedoch für das beliebte npm-Paket jsonwebtoken. Diese Bibliotheken vereinfachen das Generieren, Signieren und Überprüfen von Tokens. Um eine unsichere Verwendung und die damit verbundenen Sicherheitsrisiken zu vermeiden, ist es jedoch entscheidend, die Unterschiede bei Funktionen und Sicherheitsaspekten zu kennen.

Weitere JSON-npm-Pakete sind node-jose sowie Integrationen für Web-Frameworks wie passport-jwt und @fastify/jwt.

JWT-Sicherheitsrisiken beim Decodieren eines Tokens

Um einen klassischen Fehler bei der unsicheren Verwendung von JWTs zur Authentifizierung zu veranschaulichen, verwenden wir die beliebten Optionen, zu denen die meisten Entwicklerinnen und Entwickler greifen: das Web-Framework Express und jsonwebtoken als JWT-Bibliothek.

Erkennen Sie die Sicherheitslücke im folgenden Node.js-Code?

const express = require('express');
const jsonWebToken = require('jsonwebtoken');
require('dotenv').config();

const webApp = express();

const securityKey = process.env.JWT_SECRET;

const validateAccess = (request, response, next) => {
  const authorizationHeader = request.headers.authorization;

  if (!authorizationHeader) {
    return response.status(401).json({ error: 'Missing authentication credentials' });
  }

  try {
    const decodedToken = jsonWebToken.decode(authorizationHeader,{complete: true});
    request.userContext = decodedToken;
    next();
  } catch (authError) {
    return response.status(403).json({ error: 'Invalid or expired token' });
  }
};

webApp.get('/privileged-area', validateAccess, (request, response) => {
  const { username } = request.userContext;
  if (username === 'admin') {
    // Access to sensitive data is now available.
    return response.status(200).json({ status: 'Access permitted to admin' });
  }
  response.status(403).json({ status: 'Insufficient permissions' });
});

webApp.get('/issue-token', (request, response) => {
  const userClaims = { username: 'user' };
  const authenticationToken = jsonWebToken.sign(userClaims, securityKey, { expiresIn: '1h' });
  response.status(200).json({ authenticationToken });
});

webApp.listen(3001, () => {
  console.log('Application listening on port 3001');
});

Dieser Node.js-Code verwendet jsonWebToken.decode(), um das JWT zu decodieren. Diese Methode decodiert das Token lediglich, ohne dessen Signatur zu überprüfen. Auch wenn der Code funktioniert, weil decodedToken Daten zurückgibt, ist nicht gewährleistet, dass diese Daten tatsächlich vom Server stammen und nicht von Dritten manipuliert wurden. Das bedeutet, dass jede Person das Token verändern kann und die Anwendung es trotzdem als gültig akzeptiert. Verwenden Sie stattdessen jsonWebToken.verify(), um das Token zu decodieren und anhand des geheimen Schlüssels zu verifizieren.

Snyk erkennt JWT-Sicherheitsprobleme

Lassen Sie den anfälligen Node.js-Code oben von Snyk analysieren. Dabei wird das JWT-Sicherheitsproblem erkannt, das durch die unsichere JSON-Web-Token-Methode jwt.decode() in der Bibliothek jsonwebtoken entsteht:

Snyk erkennt ein JWT-Sicherheitsproblem, bei dem ein Token unsicher dekodiert wird

Snyk erkennt das Problem unabhängig davon, wo Sie die Integration vornehmen. Im Screenshot oben habe ich das GitHub-Code-Repository über die Snyk-Web-App importiert. Nach dem Import scannt Snyk das Repository nach Manifestdateien wie beispielsweise requirements.txt von Python oder package.json von npm, um anfällige Abhängigkeiten zu erkennen. Snyk erkennt auch IaC-Dateien wie Terraform-Dateien und führt eine statische Codeanalyse durch, bei der der Code selbst untersucht wird.

Wie Sie im Screenshot oben sehen, hat Snyk die missbräuchliche Verwendung von Bibliothekscode in jsonwebtoken erkannt. Dieser verwendet die unsichere Funktion jwt.decode, die zu einer fehlerhaften Authentifizierung führen kann.

So decodieren Sie ein JWT sicher:

   try {
     const decodedToken = jsonWebToken.verify(authorizationHeader, securityKey);
     request.userContext = decodedToken;
     next();
   } catch (authError) {
     return response.status(403).json({ error: 'Invalid or expired token' });
   }

Zu den weiteren JWT-Sicherheitsproblemen im obigen Node.js-Beispielcode gehören folgende Schwachstellen:

  • Fest codierte vertrauliche Daten: Der Codeausschnitt speichert den geheimen Schlüssel in Umgebungsvariablen. Stellen Sie sicher, dass diese Umgebungsvariablen sicher verwaltet und nicht in Versionskontrollsystemen offengelegt werden und dass Sie sie rotieren und sicher verwalten können.

  • Unzureichende Protokollierung: Protokollieren Sie Authentifizierungsversuche und Fehler. So können Sie potenzielle Sicherheitsvorfälle überwachen und darauf reagieren.

  • Ratenbegrenzung: Wie lassen sich Brute-Force-Anmeldeversuche und anderer Missbrauch von Authentifizierungs-APIs kontrollieren? Implementieren Sie eine Ratenbegrenzung, um Ressourcenüberlastung und unbegrenzte Authentifizierungsversuche zu verhindern.

  • Token-Ablauf: Der Code legt zwar eine Ablaufzeit für Tokens fest, doch Sie müssen bei jeder Anfrage überprüfen, ob das Token abgelaufen ist.

Empfohlene JWT-Sicherheits-Best-Practices

Eine REST-API mit JWT abzusichern, bedeutet mehr, als nur Tokens auszustellen und zu überprüfen. Um potenzielle Schwachstellen zu minimieren, müssen mehrere Sicherheitspraktiken sorgfältig berücksichtigt werden. Verwenden Sie beispielsweise stets einen starken geheimen Schlüssel zum Signieren von Tokens, vorzugsweise asymmetrische Schlüssel, und stellen Sie sicher, dass Tokens über HTTPS übertragen werden, um ein Abfangen zu verhindern.

Außerdem sind geeignete Strategien für den Ablauf und den Widerruf von Tokens entscheidend. Tokens sollten eine kurze Gültigkeitsdauer haben, um das Missbrauchsrisiko bei einer Kompromittierung zu minimieren. Mit Refresh-Tokens können neue Access-Tokens ausgestellt werden, ohne dass sich der Benutzer erneut anmelden muss. Auch diese müssen jedoch sicher verwaltet werden.

Weitere Informationen finden Sie in unserem ausführlichen Leitfaden zur Absicherung von REST-APIs.

KI-CODE-SICHERHEIT

Käuferleitfaden zur Code-Sicherheit bei generativer KI

Erfahren Sie in Snyks Käuferleitfaden zur Code-Sicherheit bei generativer KI, wie Sie Ihren KI-generierten Code schützen.

Gepostet in: