Authentifizierung klingt im Alltag einfach: „Login mit Username und Passwort." In einer modernen Web-App ist das aber nur ein winziger Ausschnitt einer Architektur, die mehrere Entscheidungen trifft — welche Faktor-Klassen akzeptiert werden, ob Sessions oder Tokens genutzt werden, wie Re-Auth für sensible Aktionen aussieht. Dieser Artikel sortiert die Begriffe und legt die Grundlagen für die folgenden Kapitel zu Hashing, Cookies, JWT und OAuth.
Authentifizierung vs. Autorisierung
Die beiden Begriffe werden täglich verwechselt — auch im Code-Review, auch in Audits.
| Begriff | Frage | Beispiel |
|---|---|---|
| Authentifizierung (AuthN) | „Wer bist du?" | Login mit Passwort, Passkey, OAuth-Provider |
| Autorisierung (AuthZ) | „Was darfst du?" | Darf User X den Datensatz Y editieren? |
| Audit | „Was hast du gemacht?" | Logging aller Aktionen für Forensik |
Konkretes Beispiel:
Ein User loggt sich erfolgreich ein — AuthN passt. Dann versucht er, das Profil eines anderen Users zu bearbeiten — AuthZ muss separat prüfen, ob das erlaubt ist. Viele klassische Bugs (IDOR, BOLA) entstehen, weil AuthN passiert ist und der Code daraus fälschlich auf AuthZ schließt.
Konsequenz für die Architektur: Auth-Logik und Permission-Logik sollten getrennte Schichten sein. Auth-Middleware setzt den User-Kontext; Permission-Checks erfolgen pro Endpoint oder pro Ressource. Vertieft in Kap 15 Autorisierung-Grundlagen.
Die drei Faktor-Klassen
Authentifizierungs-Faktoren werden traditionell in drei Klassen eingeteilt:
| Klasse | Was es ist | Beispiele | Schwächen |
|---|---|---|---|
| Wissen | Etwas, das du weißt | Passwort, PIN, Sicherheits-Fragen | Phishable, ratbar, wiederverwendbar |
| Besitz | Etwas, das du hast | Smartphone, Hardware-Token, Smartcard | Verlierbar, klonbar (SIM-Swap) |
| Inhärenz | Etwas, das du bist | Fingerabdruck, Gesicht, Iris | Nicht änderbar bei Kompromittierung, lokal verifiziert |
Multi-Faktor-Authentifizierung (MFA) kombiniert mindestens zwei verschiedene Klassen — Passwort + SMS sind formal zwei Faktoren (Wissen + Besitz), aber SMS ist anfällig für SIM-Swapping und gilt nicht mehr als starker zweiter Faktor.
Moderner Konsens (Stand 2026):
- Phishing-resistente MFA ist Pflicht für sensible Konten — das heißt WebAuthn/FIDO2-Passkeys oder Hardware-Tokens (YubiKey).
- TOTP-Apps (Google Authenticator, Aegis, Raivo) sind besser als SMS, aber Phishing-anfällig (Adversary-in-the-Middle kann TOTP-Code in Echtzeit abfragen).
- SMS-MFA ist veraltet — nur noch als Notlösung akzeptabel, niemals als einziger zweiter Faktor.
- Passkeys (siehe webauthn-und-passkeys) sind die strukturelle Antwort: Phishing-resistent, Cross-Device-Sync, kein Passwort mehr.
Session-basiert vs. Token-basiert
Zwei dominante Architektur-Patterns für „User ist eingeloggt":
Session-basiert (klassisch):
# Login-Response setzt Cookie
Set-Cookie: sessionId=opaque-random-id; HttpOnly; Secure; SameSite=Lax
# Jeder Folge-Request schickt Cookie mit
Cookie: sessionId=opaque-random-id
# Server schlägt sessionId in Session-Store (DB/Redis) nach
# → User-Kontext, BerechtigungenToken-basiert (stateless):
# Login-Response liefert Token
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6...
# (signiertes JWT mit User-Info im Payload)
# Jeder Folge-Request schickt Token im Header
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6...
# Server validiert Signatur, liest Payload — kein DB-Lookup nötig| Aspekt | Session-basiert | Token-basiert (JWT) |
|---|---|---|
| State | Server-Side (Session-Store) | Stateless (Token enthält State) |
| Revocation | Sofort (Eintrag löschen) | Schwierig (Token bleibt valide bis exp) |
| Skalierung | Session-Store ist Single Point | Beliebige Backend-Instanzen |
| CSRF-Schutz | Cookie + CSRF-Token nötig | Header-basiert: Header sendet Browser nicht automatisch |
| XSS-Auswirkung | Cookie mit HttpOnly schützt vor JS-Zugriff | Token meist in JS zugänglich → XSS = Token-Diebstahl |
| Mobile/SPA | Funktioniert, etwas umständlich | Default-Pattern |
| Klassischer Web-Login | Default-Pattern | Möglich, aber overkill |
Konsequenzen für die Wahl:
- Klassische Web-App mit Server-Render: Sessions sind einfacher und sicherer. CSRF-Schutz ist Standard-Pattern. Vertieft in session-cookies und Kap 12 CSRF.
- SPA + API: Beides funktioniert. Mit
HttpOnly-Cookies (auch für SPAs) hast du Sessions plus CSRF-Schutz; mit JWT inAuthorization-Header hast du Stateless plus CORS-Komplexität. - Microservices / Service-to-Service: Token (JWT, mTLS) ist der Standard — Cookies funktionieren in B2B-Service-Calls nicht gut.
- Mobile-App: Token ist Standard, weil Mobile-HTTP-Clients selten Cookie-Stores haben.
Vorsicht vor „JWT überall" als Default: JWT hat viele Spezial-Probleme (siehe jwt-stateless-tokens). Für klassische Web-Apps ist Session-basiert oft die bessere Wahl.
Login-Flow als Minimalbeispiel
Ein einfacher passwort-basierter Login-Flow zeigt die Grundbausteine:
const argon2 = require('argon2');
const crypto = require('crypto');
app.post('/login', async (req, res) => {
const { email, password } = req.body;
// 1. User aus DB laden (Konstante Zeit — Enumeration-Schutz)
const user = await db.users.findOne({ email });
// 2. Passwort-Hash vergleichen (auch wenn user null ist — Timing)
const passwordHash = user?.passwordHash || DUMMY_HASH;
const ok = await argon2.verify(passwordHash, password);
if (!user || !ok) {
// 3. Generische Fehlermeldung — keine Information über Existenz
return res.status(401).json({ error: 'Invalid credentials' });
}
// 4. Session-ID erzeugen (kryptografisch zufällig)
const sessionId = crypto.randomBytes(32).toString('base64url');
await sessionStore.set(sessionId, {
userId: user.id,
createdAt: Date.now(),
lastActivity: Date.now(),
}, { ttlMs: 24 * 60 * 60 * 1000 });
// 5. Cookie setzen
res.cookie('sessionId', sessionId, {
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 24 * 60 * 60 * 1000,
});
// 6. Audit-Log
logger.info('login.success', {
userId: user.id,
ip: req.ip,
userAgent: req.get('user-agent'),
});
res.json({ ok: true });
});Was hier alles steckt:
- Hashing mit argon2id (siehe passwort-hashing).
- Konstante-Zeit-Vergleich plus Dummy-Hash gegen User-Enumeration via Timing.
- Generische Fehlermeldung — keine Unterscheidung „User existiert nicht" vs. „Passwort falsch" (siehe account-lifecycle).
- Kryptografische Session-ID — 256 Bits Entropie, base64url-encoded.
- Cookie-Flags —
HttpOnly,Secure,SameSite=Lax(siehe session-cookies). - Audit-Log für Forensik.
Was hier noch fehlt:
- Rate-Limiting — Brute-Force-Schutz (siehe brute-force-und-rate-limits).
- MFA-Step — bei aktiviertem zweiten Faktor.
- Anomalie-Detection — Login von ungewöhnlichem Standort/Gerät.
- Re-Auth-Marker für sensitive Aktionen.
Re-Authentication
Eine wichtige, oft vergessene Schicht: Re-Auth für sensitive Aktionen.
Selbst wenn der User „eingeloggt" ist, sollten kritische Operationen (Passwort ändern, E-Mail-Adresse ändern, Zahlungs-Methode anpassen, Account löschen) erneute Authentifizierung verlangen. Gründe:
- Schutz gegen aktive Session-Hijacks — Angreifer hat zwar Session, aber kein aktuelles Passwort.
- Schutz gegen Schulter-Surfen — Account, der eingeloggt ist, soll trotzdem nicht spontan löschbar sein.
- Audit-Trail — Re-Auth-Events sind separat geloggt, klare Spuren.
Implementierungs-Pattern:
// Marker in Session: wann zuletzt Re-Auth gemacht?
session.lastReAuthAt = Date.now();
// Middleware für sensitive Endpoints
function requireFreshAuth(maxAgeMs = 5 * 60 * 1000) {
return (req, res, next) => {
const lastReAuth = req.session.lastReAuthAt || req.session.createdAt;
if (Date.now() - lastReAuth > maxAgeMs) {
return res.status(403).json({ error: 'Re-Authentication required' });
}
next();
};
}
app.post('/account/delete', requireFreshAuth(), async (req, res) => {
// ...
});Faustregel: Innerhalb von 5–15 Minuten nach letzter Authentifizierung gelten sensible Aktionen als erlaubt; danach Re-Auth verlangen.
Anonymisierte und Service-Accounts
Nicht jeder Auth-Kontext ist ein menschlicher User.
Anonyme Sessions:
Ein User kann eine anonyme Session haben (Warenkorb vor Login). Diese hat eine Session-ID, aber kein userId. Beim Login wird die anonyme Session mit dem User-Account gemergt — der Warenkorb bleibt erhalten. Vorsicht: Session-Fixation-Schutz (siehe session-cookies) muss eine neue Session-ID nach Login generieren, sonst kann ein Angreifer eine anonyme Session vorbereiten und auf das Login warten.
Service-Accounts / API-Keys:
Wenn nicht ein User, sondern ein anderer Service Auth braucht (Microservice-Aufruf, externes System mit API-Zugang):
- API-Keys — langlebige Bearer-Tokens, simpel, gefährlich bei Leak.
- mTLS — Client-Zertifikate, robust, höherer Setup-Aufwand.
- OAuth-Client-Credentials-Flow — JWT-basiert, mit Scope-Beschränkung.
Vertieft in Kap 18 api-keys-vs-tokens.
Was Auth NICHT löst
Ein verbreiteter Trugschluss: „Wir haben Auth, also sind wir sicher." Auth löst nur einen Ausschnitt:
- Auth identifiziert den User — sagt aber nichts darüber, ob seine Aktionen erlaubt sind (AuthZ).
- Auth verhindert nicht XSS — wenn der User-Code im Browser geknackt wird, kann der Angreifer im Namen des Users handeln (siehe Kap 11).
- Auth verhindert nicht CSRF — eingeloggter User kann von fremden Sites ausgenutzt werden, wenn keine CSRF-Token gesetzt sind (siehe Kap 12).
- Auth verhindert nicht IDOR — eingeloggter User A kann auf Daten von User B zugreifen, wenn Resource-Owner-Checks fehlen (siehe Kap 15 idor-und-bola).
- Auth verhindert nicht Account-Übernahme — Phishing, Password-Reuse, SIM-Swap, Recovery-Lücken bleiben Vektoren.
Auth ist eine Schicht — nicht die Sicherheit.
Standards und Frameworks
Für Web-Auth gibt es etablierte Standards und Library-Familien:
| Standard / Lib | Was es löst | Wann nutzen |
|---|---|---|
| NIST SP 800-63B | Digital Identity Guidelines | Compliance-Anforderungen, MFA-Level (AAL1/2/3) |
| OAuth 2.1 / RFC 9700 | Delegated Authorization | Drittanbieter-Zugriff, Login-with-X |
| OIDC 1.0 | Identity-Layer auf OAuth | SSO, Login-with-X mit User-Info |
| WebAuthn L3 | Phishing-resistente Auth | Passkeys, Hardware-Keys |
| SAML 2.0 | XML-basiertes SSO | Enterprise-SSO, Legacy |
| Passport.js | Node.js-Auth-Middleware | Express/Fastify-Apps mit Multi-Strategy-Login |
| Devise | Rails-Auth-Library | Rails-Apps |
| Django auth | Built-in | Django-Apps |
| NextAuth.js / Auth.js | Next.js Auth | Next.js-Apps mit OAuth-Providers |
| Keycloak / Ory / Authelia | Standalone Identity-Provider | Microservices-Stacks, Self-Hosted SSO |
| Auth0 / Okta / Clerk | SaaS-Identity-Provider | Wenn Auth nicht selbst betrieben werden soll |
Empfehlung: Auth-Kern niemals selbst implementieren. Für klassische Web-Apps eine etablierte Library nutzen (Django, Devise, Passport, NextAuth). Für Microservices ein Identity-Provider (Keycloak, Ory) oder ein SaaS (Auth0). Die meisten Auth-CVEs entstehen in selbst-gebautem Code.
Interessantes
NIST SP 800-63B Authentication Assurance Levels (AAL)
Die NIST-Klassifizierung unterteilt Auth in drei Sicherheits-Stufen: AAL1 (mindestens ein Faktor), AAL2 (zwei verschiedene Faktoren, MFA-Pflicht), AAL3 (Hardware-basierter zweiter Faktor, Phishing-resistent — also FIDO2/WebAuthn oder vergleichbar). Compliance-Anforderungen (z. B. NIST SP 800-63B) referenzieren diese Stufen direkt.
Passkeys sind die kommende Default-Methode
Apple, Google und Microsoft haben Passkey-Support flächendeckend ausgerollt; passkeys.dev dokumentiert den Stack. 2025/2026 ist der Konsens: passwort-basierte Logins ergänzen, nicht ersetzen — aber neu gebaute Auth-Flows sollten Passkeys von Anfang an unterstützen, nicht nachrüsten. Vertieft in webauthn-und-passkeys.
"Magic Link" als passwortloser Workflow
Statt Passwort: User gibt E-Mail an, bekommt Link in der Mail, klickt — eingeloggt. Beispiele: Slack, Notion, Medium. Vorteile: kein Passwort-Storage, kein Reset-Flow. Nachteile: Mail-Account-Sicherheit wird zum Single Point, Link-Hijacking bei Mail-Konto-Übernahme. Sinnvoll als zusätzliche Methode neben Passkey/Passwort, selten als einzige.
Login as User für Support — fast immer falsch implementiert
Support-Teams brauchen manchmal einen „Impersonate User"-Modus. Klassisches Pattern: Admin-User generiert eine kurzfristige Token, die einen anderen User-Kontext bekommt. Fallen: (1) keine Trennung des Logging-Kontexts (Aktion erscheint als vom echten User), (2) keine Re-Auth, (3) keine Zeitbegrenzung, (4) keine Zustimmung des Endusers. Saubere Implementierung: separater Session-Flag „impersonated_by", expliziter Audit-Log, kurzer Time-Limit, idealerweise mit User-Notification.
OWASP ASVS als praktischer Checklist-Standard
Der OWASP ASVS (Application Security Verification Standard) hat in Kapitel V2/V3 detaillierte Auth-Anforderungen pro Sicherheits-Level. Praktisch für: Selbst-Audit, Lasten-/Pflichtenheft, Security-Reviews mit dem Team. Stand 2026: ASVS 5.0.
Account-Linking ist eine eigene Klasse
Wenn ein User mit Google-Login UND mit Passwort einloggen kann — wer „besitzt" den Account? Klassische Lücke: Angreifer registriert mit Passwort auf Mail-Adresse des Opfers, Opfer macht später Google-Login, beide landen im selben Account — Angreifer hat Zugriff. Saubere Implementierung: E-Mail-Verifikation vor Account-Aktivierung, kein automatisches Linking ohne explizite User-Aktion.
Weiterführende Ressourcen
Externe Quellen
- OWASP Authentication Cheat Sheet
- NIST SP 800-63B — Digital Identity Guidelines
- OWASP ASVS — Application Security Verification Standard
- RFC 9700 — OAuth 2.0 Security Best Current Practice
- passkeys.dev — Passkeys-Implementation-Guide
- RFC 9110 — HTTP Semantics (Authentication)
- Passport.js — Node.js Auth-Middleware
- Auth.js (NextAuth) — Next.js Auth-Library
Verwandte Artikel
- Passwort-Hashing
- Session-Cookies
- JWT und Stateless Tokens
- OAuth 2.1 und OIDC
- WebAuthn und Passkeys
- Account-Lifecycle
- Brute-Force und Rate-Limits
- Autorisierung-Grundlagen (Kap 15)
- CSRF-Grundlagen (Kap 12)
- Passkeys für Nutzer (Kap 2 — Nutzer-Sicht)