Verbesserung der Token-basierten Authentifizierung in Python-APIs mit knox und FastAPI-Users
Lukas Schneider
DevOps Engineer · Leapcell

Einführun
In der Landschaft der modernen Webentwicklung ist die API-Sicherheit von größter Bedeutung. Da Anwendungen immer verteilter werden und Architekturen mit Microservices an Bedeutung gewinnen, sind robuste Authentifizierungsmechanismen nicht mehr nur ein Luxus, sondern eine Notwendigkeit. Die tokenbasierte Authentifizierung hat sich aufgrund ihrer Zustandsunabhängigkeit, Skalierbarkeit und Eignung für mobile Anwendungen und Single-Page-Anwendungen als bevorzugte Methode zur Sicherung von APIs etabliert. Die bloße Verwendung von Tokens reicht jedoch nicht aus; die Verwaltung ihres Lebenszyklus, die Gewährleistung ihrer Vertraulichkeit und die Minderung gängiger Angriffsvektoren erfordern sorgfältige Überlegungen. Dieser Artikel befasst sich damit, wie zwei leistungsstarke Frameworks, django-rest-knox
für Django REST Framework und FastAPI-Users
für FastAPI, erweiterte Sicherheitsfunktionen für die Token-Authentifizierung bieten und über grundlegende Implementierungen hinausgehen, um widerstandsfähigere und entwicklerfreundlichere Lösungen anzubieten.
Kernkonzepte der sicheren Token-Authentifizierung
Bevor wir uns mit den Besonderheiten von django-rest-knox
und FastAPI-Users
befassen, wollen wir einige grundlegende Konzepte klären, die für das Verständnis sicherer Token-Authentifizierung unerlässlich sind.
Token-basierte Authentifizierung
Im Kern sendet ein Client Anmeldeinformationen (wie Benutzername und Passwort) an einen Authentifizierungsserver. Nach erfolgreicher Überprüfung stellt der Server einen verschlüsselten Token aus. Dieser Token, typischerweise ein JSON Web Token (JWT) oder ein opaker Token, wird dann auf der Client-Seite gespeichert und bei jeder nachfolgenden Anfrage zur Anforderung geschützter Ressourcen gesendet. Der Server validiert den Token, um den Benutzer für jede Anfrage zu authentifizieren.
Opake Tokens vs. JWTs
- Opake Tokens: Dies sind zufällige Zeichenfolgen, die als Referenzen auf Serverseitig gespeicherte Authentifizierungssitzungen fungieren. Der Token selbst enthält keine Benutzerinformationen; der Server schlägt den Token in einer Datenbank nach, um Sitzungsdetails abzurufen. Dies ermöglicht die serverseitige Sperrung und einfachere Ungültigkeitserklärung.
- JWTs (JSON Web Tokens): Diese Tokens enthalten kodierte JSON-Objekte mit Benutzeransprüchen (Informationen über den Benutzer) und einer Signatur. Der Server kann die Authentizität des Tokens überprüfen, ohne jedes Mal eine Datenbank abfragen zu müssen, solange er über den Signaturschlüssel verfügt. Während JWTs effizient sind, sind sie schwieriger sofort zu sperren, wenn sie eine lange Ablaufzeit haben.
Wichtige Sicherheitsprobleme mit Tokens
- Brute-Force-Angriffe: Wiederholte Versuche, Tokens oder Anmeldeinformationen zu erraten.
- Replay-Angriffe: Ein Angreifer fängt einen Token ab und verwendet ihn erneut, um unbefugten Zugriff zu erhalten.
- Token-Hijacking/Diebstahl: Ein Angreifer erlangt Besitz eines gültigen Tokens, oft durch Cross-Site Scripting (XSS) oder Man-in-the-Middle-Angriffe.
- Unsachgemäße Token-Sperrung: Tokens bleiben gültig, nachdem sich ein Benutzer abgemeldet hat oder seine Sitzung beendet werden sollte.
- Unsichere Speicherung: Tokens werden an anfälligen Stellen auf der Client-Seite gespeichert.
Die diskutierten Frameworks zielen darauf ab, diese Probleme durch ihr Design und ihre Funktionen zu lösen.
Sicherheit verbessern mit django-rest-knox
django-rest-knox
ist ein Paket für Django REST Framework (DRF), das ein sicheres, tokenbasiertes Authentifizierungssystem bietet. Im Gegensatz zur integrierten TokenAuthentication
von DRF, die einen einzelnen, persistenten Token ausstellt, konzentriert sich knox auf Einweg-, ablaufende und leicht sperrbare Tokens. Es verwendet hauptsächlich opake Tokens.
Funktionsweise von django-rest-knox
- Token-Generierung: Wenn sich ein Benutzer anmeldet, generiert knox einen eindeutigen, kryptographisch sicheren opaken Token. Es speichert einen Hash dieses Tokens zusammen mit seinem Ablaufdatum in der Datenbank.
- Client-Seite: Der Klartext-Token wird an den Client gesendet. Der Client speichert diesen Token (z. B. in
localStorage
odersessionStorage
für Web-Apps, sicheren Speicher für mobile Apps). - Authentifizierung: Für nachfolgende Anfragen sendet der Client diesen Token im
Authorization
-Header. - Überprüfung: Der Server empfängt den Token, hasht ihn und vergleicht ihn mit dem in der Datenbank gespeicherten Hash. Wenn eine Übereinstimmung gefunden wird und der Token nicht abgelaufen ist, wird der Benutzer authentifiziert.
- Einmalige Verwendung/Sperrung: KNOX ermöglicht die Token-Sperrung bei Abmeldung oder nach Ablauf. Entscheidend ist, dass es Multi-Geräte-Logins unterstützt, indem es mehrere Tokens pro Benutzer zulässt, und Mechanismen zur Sperrung aller Tokens für einen Benutzer oder eines bestimmten Tokens bietet.
Implementierungsbeispiel mit django-rest-knox
Installieren Sie zunächst django-rest-knox
:
pip install django-rest-knox
Fügen Sie knox
zu Ihren INSTALLED_APPS
in settings.py
hinzu:
# settings.py INSTALLED_APPS = [ # ...weitere Apps 'rest_framework', 'knox', ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'knox.auth.TokenAuthentication', ), # ... }
Integrieren Sie die URLs von Knox in die urls.py
Ihres Projekts:
# urls.py from django.contrib import admin from django.urls import path, include from knox import views as knox_views from .views import LoginAPI # Angenommen, Sie haben eine benutzerdefinierte LoginAPI-Ansicht urlpatterns = [ path('admin/', admin.site.urls), path('api/auth/login/', LoginAPI.as_view(), name='knox_login'), path('api/auth/logout/', knox_views.LogoutView.as_view(), name='knox_logout'), path('api/auth/logoutall/', knox_views.LogoutAllView.as_view(), name='knox_logoutall'), # ...weitere API-Endpunkte ]
Erstellen Sie eine benutzerdefinierte LoginAPI
-Ansicht zur Behandlung von Benutzeranmeldung und Token-Generierung:
# Ihr_app/views.py from rest_framework import generics, permissions from rest_framework.response import Response from knox.models import AuthToken from .serializers import UserSerializer, AuthTokenSerializer class LoginAPI(generics.GenericAPIView): serializer_class = AuthTokenSerializer permission_classes = (permissions.AllowAny,) def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] _, token = AuthToken.objects.create(user) # Erstellt einen Token und gibt das Benutzerobjekt und den Token-String zurück return Response({