Cookies sind die älteste Web-Storage-Schicht und gleichzeitig das wichtigste Auth-Vehikel. Die Anzahl der Attribute und Quirks ist groß: Secure, HttpOnly, SameSite, Path, Domain, Max-Age, Expires, die strukturellen Präfixe __Host- und __Secure-, plus der seit 2024 verbreitete Partitioned-Flag für Storage-Partitioning. Dieser Artikel liefert eine vollständige Referenz inkl. Quirks pro Browser.

HTTP cookie-anatomy.txt
Set-Cookie: name=value;
            Domain=example.com;
            Path=/;
            Max-Age=86400;
            Expires=Mon, 17 May 2027 12:00:00 GMT;
            HttpOnly;
            Secure;
            SameSite=Lax;
            Partitioned

Pro Cookie ein Set-Cookie-Header (mehrere Cookies = mehrere Header).

AttributWertDefaultBedeutung
DomainDomain-Stringaktueller Host (Host-Only)Cookie gilt für diese Domain plus Subdomains
PathPfad-String/ (bzw. Request-Pfad)Cookie nur für diesen Pfad und Sub-Pfade
Max-AgeSekunden(kein Default)Lebenszeit ab jetzt (überschreibt Expires)
ExpiresDatum(kein Default)Absoluter Ablauf-Zeitpunkt
Secure(boolean)ausNur über HTTPS senden
HttpOnly(boolean)ausJS via document.cookie kann nicht lesen
SameSiteStrict/Lax/NoneLax (modern)Cross-Site-Verhalten
Partitioned(boolean)ausCookie wird pro Top-Frame-Site partitioniert (CHIPS)
PriorityLow/Medium/HighMediumBrowser-Eviction-Reihenfolge (Chromium-only)

Secure, HttpOnly, SameSite — die drei Sicherheits-Flags

Vertieft in session-cookies (Kap 14). Hier nochmal kompakt:

Secure — Cookie wird nur über HTTPS gesendet. Pflicht für alle Auth-Cookies. Lokales localhost ohne TLS akzeptiert Secure als Default (moderne Browser).

HttpOnly — JS via document.cookie kann den Cookie nicht lesen. Pflicht für Session-Cookies — gegen XSS-Cookie-Diebstahl. Limitation: schützt nicht vor XSS-via-fetch-with-credentials.

SameSite — Cross-Site-Verhalten:

  • Strict — nie bei Cross-Site-Requests. Klick auf externen Link zur Seite → kein Cookie → User scheint nicht eingeloggt.
  • Lax (Default seit 2020) — bei Cross-Site nur bei Top-Level-GET. Klassische CSRF-Schutz-Schicht.
  • None — immer, auch Cross-Site. Erfordert Secure-Flag.

Mehr in samesite-cookies (Kap 12).

Path und Domain

Path — Cookie gilt nur für Requests, deren URL mit diesem Pfad beginnt. Default ist der Pfad des Set-Cookie-Requests.

  • Path=/ — gilt überall.
  • Path=/api — gilt für /api, /api/users, /api/v2/....
  • Path=/admin — gilt nur für Admin-Bereich.

Wichtig: Path ist kein Sicherheits-Mechanismus. Der Browser sendet das Cookie nur an passenden Pfaden, aber JS auf der Seite kann mit document.cookie Cookies nicht-passender Pfade trotzdem nicht sehen — heißt nicht, dass andere Pfade „sicher" vor diesem Cookie sind.

Domain — wenn nicht gesetzt: Host-Only-Cookie (gilt nur für exakt diesen Host).

Wenn gesetzt: gilt für diese Domain plus alle Subdomains.

HTTP cookie-domain-behavior.txt
# Auf app.example.com gesetzt, OHNE Domain
Set-Cookie: x=1
→ gilt nur für app.example.com

# Auf app.example.com gesetzt MIT Domain=example.com
Set-Cookie: x=1; Domain=example.com
→ gilt für example.com, app.example.com, blog.example.com, beliebige.example.com

Sicherheits-Implication: wer Domain=example.com setzt, gibt Subdomain-Sicht. Wenn blog.example.com XSS hat, sieht JS dort das Cookie. Empfehlung: Domain weglassen außer wenn explizit Multi-Subdomain-Sharing gewollt ist.

__Host- und __Secure-Präfixe

Browser-erzwungene Garantien per Naming-Convention.

__Host--Präfix:

Cookies mit Namen __Host-... werden vom Browser nur akzeptiert, wenn:

  • Secure gesetzt.
  • Path=/ gesetzt.
  • Kein Domain-Attribut (Host-Only).
HTTP host-prefix-cookie.txt
Set-Cookie: __Host-sessionId=abc; Secure; HttpOnly; SameSite=Lax; Path=/
# Browser akzeptiert ✓

Was es garantiert:

  • Cookie kann nur über HTTPS gesendet werden.
  • Cookie ist auf den exakten Host beschränkt — keine Subdomain kann es schreiben oder lesen.
  • Cookie ist für die ganze Site gültig (Path=/).

Wenn der Server ein __Host--Cookie ohne die Bedingungen setzt, lehnt der Browser das Cookie ab — kein Set-Cookie wirksam. Strukturelle Garantie.

__Secure--Präfix:

Schwächer als __Host-. Cookies mit Namen __Secure-... werden nur akzeptiert, wenn Secure gesetzt ist. Erlaubt Domain und Path != /.

Empfehlung: Für Session-Cookies __Host--Präfix nutzen. Für andere sicherheits-relevante Cookies (CSRF-Token, Refresh-Token, etc.) ebenfalls.

Max-Age und Expires

Beide steuern die Cookie-Lebenszeit:

  • Max-Age in Sekunden (z. B. Max-Age=86400 = 1 Tag). Relativ zur Set-Zeit.
  • Expires als absolutes Datum (RFC 1123 / RFC 7231 Format).
  • Wenn beide gesetzt: Max-Age gewinnt (in modernen Browsern).
  • Wenn keines gesetzt: Session-Cookie — wird beim Browser-Schließen gelöscht (in der Theorie; Browser mit „Session restore on restart" behalten sie de facto).

Sicherheits-Implikation:

  • Auth-Cookies sollten explizites Max-Age haben (typisch 1 Tag bis 1 Woche).
  • Sehr lange Lebenszeiten (1 Jahr+) sind ein Risiko — bei Cookie-Diebstahl bleibt der Zugang lange offen.
  • Session-Cookies ohne Max-Age klingen sicher, sind aber bei „Restore Session"-Verhalten praktisch persistent.

Cookie-Löschung:

HTTP cookie-deletion.txt
# Cookie mit Vergangenheits-Datum oder Max-Age=0 wird gelöscht
Set-Cookie: name=; Path=/; Max-Age=0
Set-Cookie: name=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT

# WICHTIG: alle Attribute (Path, Domain) müssen mit dem ursprünglichen Cookie übereinstimmen,
# sonst wird ein NEUES Cookie gesetzt statt das alte gelöscht

Partitioned (CHIPS) — Storage-Partitioning

Seit 2024 verbreitet: Cookies Having Independent Partitioned State (CHIPS).

Problem: Drittpartei-Cookies sind in modernen Browsern stark eingeschränkt (Safari ITP seit 2017, Chrome 2024). Manche legitime Use-Cases (Embed-Widgets, SSO-iframes) brauchen aber Cookie-Storage in cross-site Kontexten.

CHIPS-Lösung: Cookie mit Partitioned-Flag wird pro Top-Frame-Site partitioniert.

HTTP partitioned-cookie.txt
Set-Cookie: widget_pref=dark; SameSite=None; Secure; Partitioned

Effekt: wenn das Widget von widget.example.com auf siteA.com eingebettet ist, gibt es ein partitioniertes Cookie für die Kombination (widget.example.com, siteA.com). Beim Embed auf siteB.com ist es ein anderer, separater Cookie-Storage.

Wann nutzen:

  • 3rd-Party-Widgets (Embed-Maps, Chat-Widgets, Embed-Videos), die User-Preferences pro Hosting-Site brauchen.
  • 3rd-Party-Auth-Widgets (limitiert — Cross-Site-SSO ist mit Partitioning eingeschränkt).

Wann nicht:

  • 1st-Party-Auth-CookiesPartitioned ist da überflüssig oder kontraproduktiv.

Konfiguration in den wichtigsten Frameworks

Express:

JavaScript express-cookie.js
res.cookie('sessionId', sessionId, {
  httpOnly: true,
  secure: true,
  sameSite: 'lax',
  path: '/',
  maxAge: 24 * 60 * 60 * 1000,  // in ms (anders als HTTP-Header in Sekunden!)
  // Für __Host-Präfix: Cookie-Name beginnt mit __Host-
});

// Mit __Host-Präfix
res.cookie('__Host-sessionId', sessionId, {
  httpOnly: true,
  secure: true,
  sameSite: 'lax',
  path: '/',
});

Django:

Python django-cookie.py
response.set_cookie(
    '__Host-sessionid',
    value=session_id,
    max_age=86400,
    secure=True,
    httponly=True,
    samesite='Lax',
)

Spring (Java):

Java spring-cookie.java
ResponseCookie cookie = ResponseCookie.from("__Host-sessionId", sessionId)
    .httpOnly(true)
    .secure(true)
    .sameSite("Lax")
    .path("/")
    .maxAge(Duration.ofDays(1))
    .build();
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());

Pro Cookie ~4 KB. Bei mehr blockiert der Browser das Cookie still oder die Server-Request-Header werden zu groß (HTTP 431-Fehler bei strikten Reverse-Proxies).

Maximale Cookie-Anzahl pro Domain: Browser-spezifisch (typisch 50–300). Bei Apps mit vielen Cookies (Marketing-Tags) kann das eng werden.

Encoding: Cookie-Werte dürfen einige Sonderzeichen nicht enthalten (Komma, Semikolon, Whitespace, Backslash, Doppelhochkommas). Pattern: URL-encode des Werts vor Set, decode beim Read.

Cookie ohne Quotes:

HTTP cookie-encoding.txt
# OK
Set-Cookie: x=hello-world

# Problematisch (Komma wird teilweise als zweiter Cookie interpretiert)
Set-Cookie: x=hello, world

# Mit Encoding
Set-Cookie: x=hello%2C%20world

SameSite=None-Quirk: vor 2020 war SameSite=None ohne Secure möglich. Heute Pflicht — Browser akzeptiert sonst nicht. Wer es noch übersieht: Cookie wird still verworfen, Auth ist broken.

FAQ

Wann __Host- vs. __Secure-?

__Host- erzwingt zusätzlich Path=/ und Host-Only. Maximal restriktiv. Für klassische Session-Cookies einer App immer __Host-. __Secure- ist die abgeschwächte Variante, wenn du Domain oder Path != / brauchst — etwa für ein Cookie, das auch von Subdomains lesbar sein soll. Default-Wahl: __Host-.

Brauche ich noch Session-Cookies oder reichen JWTs?

Beides hat Trade-offs (siehe jwt-stateless-tokens). Für klassische Web-Apps mit Server-Rendering ist Session-Cookie mit __Host- und HttpOnly meistens einfacher und sicherer. JWTs lohnen sich bei Microservice-Architekturen und Mobile-Clients.

SameSite=Strict bricht Onboarding-Flows

Klassischer Onboarding-Flow: User registriert sich, klickt auf Verifikations-Link in Mail, landet auf der App. Wenn das Auth-Cookie SameSite=Strict ist, wird es bei Klick aus der Mail (Cross-Site) nicht gesendet — User erscheint nicht eingeloggt. Pattern: SameSite=Lax für Standard, Strict nur für sehr sensitive Bereiche (Banking-Transfer).

Wann brauche ich Partitioned-Cookies?

Wenn deine App ein Drittpartei-Widget auf fremden Sites hostet (Chat-Bubble, Calendar-Widget, Embed-Map), und du dort User-Preferences pro Hosting-Site speichern willst. Für 1st-Party-Apps (User lädt deine App direkt im Browser) ist Partitioning irrelevant.

Cookie-Banner-Pflicht (DSGVO/TTDSG)

Nicht alle Cookies brauchen Consent. Strikt notwendige (Session, Auth, Warenkorb) sind ohne Consent erlaubt (DSGVO Art. 6 Abs. 1 lit. b). Tracking-, Analytics- und Marketing-Cookies brauchen Opt-In. Cookie-Banner ist die UI-Schicht; die Cookies selbst sollten erst nach Zustimmung gesetzt werden. Vertieft in Kap 5.

Cookie-Hijacking nach DOM-Cookie-Override

Wenn ein JS-zugängliches Cookie (kein HttpOnly) den Wert eines HttpOnly-Cookies überschreibt, kommt es auf die Reihenfolge an. Browser-Behavior ist Standard: das zuletzt gesetzte gleichnamige Cookie gewinnt. Pattern: kritische Cookies immer mit __Host-Präfix und HttpOnly, plus eindeutigen Namen.

document.cookie vs. CookieStore API

Die alte API ist document.cookie — synchron, langsam. Die CookieStore API ist die moderne async Alternative, mit besserer Promise-basierter Semantik und Change-Events. Stand 2026 in Chromium und Firefox; Safari noch nicht voll. Für neue Code-Bases erwägen.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Secure Headers & Cookies

Zur Übersicht