Kurz gesagt
Liste zuerst alle Cookies deiner Website auf und notiere, wozu jedes dient. Jedes Cookie bekommt Secure, jedes, das kein Skript lesen muss, HttpOnly, und SameSite=Lax ist der übliche Ausgangswert. Das Anmelde-Cookie trägt zusätzlich das Präfix __Host-, Path=/ und keinen Domain-Eintrag — dann nimmt der Browser es nur so an. Prüfe das Ergebnis in den Entwicklerwerkzeugen und mit den Set-Cookie-Zeilen in der Werkstatt.
Worum es geht
Am Ende kennst du jedes Cookie deiner Website samt Zweck, und das Anmelde-Cookie geht nur verschlüsselt, nur an deine Adresse und nie an Skripte. Was die einzelnen Cookie-Attribute bedeuten, steht im Begriff.
Ein Beispiel: Miras Buchungsseite für ihr Yogastudio unter www.example.org läuft mit PHP. Ihre Anmeldung antwortet bisher ohne jedes Schutzattribut:
Set-Cookie: PHPSESSID=…; path=/
Ziel ist diese Zeile:
Set-Cookie: __Host-sitzung=…; Path=/; Secure; HttpOnly; SameSite=Lax
Was du brauchst
- Die Befugnis über die Website und Zugriff darauf, wo ihre Cookies entstehen.
- HTTPS auf allen Seiten: Ein Cookie mit Secure nimmt der Browser von einer unverschlüsselten Antwort gar nicht an. Dass er deine Seite nach dem ersten Besuch nur noch verschlüsselt aufruft, regelt HSTS (Strict-Transport-Security); mehr in Was HTTPS schützt — und was nicht.
- Ein Testkonto und die Abläufe, die Cookies brauchen: An- und Abmeldung, Bezahlung, Anmeldung über fremde Anbieter, eingebettete Dienste.
- Eine Sicherung der bisherigen Konfiguration als Rückweg.
- Chrome oder Firefox mit Entwicklerwerkzeugen; die Wege unten haben den Stand Oktober 2026.
1. Alle Cookies auflisten
Melde dich mit dem Testkonto an und spiele die Abläufe einmal durch; manche Cookies entstehen erst dabei. Öffne dann mit F12 die Entwicklerwerkzeuge:
- Chrome: „App“ (englisch „Application“) › „Speicher“ › „Cookies“ › deine Adresse.
- Firefox: „Web-Speicher“ › „Cookies“ › deine Adresse. Ausgeblendete Spalten zeigt ein Rechtsklick auf die Spaltenköpfe.
Notiere zu jedem Cookie, wozu es dient, ob ein Skript es lesen und ob es in fremden Seiten funktionieren muss. Cookies fremder Domains setzt der eingebundene Dienst, nicht du, und ein Cookie aus einem Skript kann kein HttpOnly tragen. Was niemand braucht, entfernst du.
2. Jedem Cookie die passenden Attribute geben
Lax schickt das Cookie beim Link von außen mit, nicht aber, wenn eine fremde Seite ein POST-Formular abschickt oder im Hintergrund etwas abruft. Schreib SameSite immer hin; auf einen Standardwert der Browser ist kein Verlass. Strict hält das Cookie auch beim Link zurück: Wer aus dem Webmailer kommt, wirkt abgemeldet. Der IETF-Entwurf schlägt deshalb zwei Cookies vor: Lax zum Lesen, Strict für Änderungen.
SameSite ersetzt keinen Schutz gegen CSRFAls dieselbe Site gelten alle Adressen derselben registrierbaren Domain, auch deine Subdomains, und Lax lässt bewusst Lücken. Formulare, die etwas verändern, brauchen weiter den Schutz deines Frameworks gegen untergeschobene Anfragen (Cross-Site Request Forgery, CSRF); mehr dazu in CORS verstehen.
3. Das Anmelde-Cookie mit __Host- schützen
Beginnt der Name mit __Host-, nimmt der Browser das Cookie nur mit Secure, Path=/ und ohne Domain-Eintrag an. Dann kann es weder eine Subdomain noch eine im Netz untergeschobene unverschlüsselte Antwort überschreiben. Müssen mehrere Subdomains dasselbe Cookie lesen, bleibt __Secure-: Es verlangt nur Secure.
Ein neuerer IETF-Entwurf ergänzt __Http- und __Host-Http-: Sie verlangen zusätzlich HttpOnly und belegen so, dass kein Skript das Cookie gesetzt hat. Chrome kennt sie seit Fassung 140, Firefox seit 143, Safari noch nicht. Willst du sie nutzen, nimm __Host-Http-: Weil der Name mit __Host- beginnt, gelten in Safari wenigstens dessen Regeln.
4. Domain, Path und Laufzeit festlegen
- Domain lässt du weg; dann geht das Cookie nur an den Hostnamen, der es gesetzt hat, nicht an Subdomains.
- Path setzt du auf /. Fehlt er, gilt nur das Verzeichnis der Adresse, ein Cookie aus /konto/anmelden etwa nur unter /konto/. Eine Schutzgrenze ist Path nicht.
- Das Anmelde-Cookie bekommt keine Laufzeit. Browser, die beim Start alte Tabs wiederherstellen, holen es zurück; ablaufen muss die Anmeldung deshalb auf dem Server.
- Länger lebende Cookies bekommen Max-Age in Sekunden; es schlägt Expires. Chrome kürzt seit Fassung 104 auf 400 Tage, wie es der Entwurf empfiehlt.
- Nach der Anmeldung vergibt der Server eine neue Sitzungskennung, damit niemand eine vorher untergeschobene weiterverwendet. Bei der Abmeldung beendet er die Sitzung bei sich und löscht das Cookie: gleicher Name, Path und Domain, bei einem Präfix auch Secure, dazu Max-Age=0.
5. Nur für eingebettete Dienste: Partitioned
Muss sich dein Dienst in fremden Seiten etwas merken, etwa als Chatfenster, setze Partitioned. Der Browser legt das Cookie dann je einbettender Website getrennt ab, sodass es einem Besucher nicht von Seite zu Seite folgt. Partitioned verlangt Secure; empfohlen sind dazu __Host-, Path=/ und SameSite=None. Chrome kann es seit Fassung 114, Firefox seit 141, Safari seit 26.2. Ob Browser ungeteilte Cookies in fremden Seiten überhaupt zulassen, steht in Wie Cookies dich über Websites hinweg verfolgen.
6. In deiner Plattform einstellen
PHP
Das Sitzungs-Cookie stellst du in der php.ini ein oder, bei FastCGI wie PHP-FPM, in der .user.ini. Path ist von Haus aus /, Domain leer; use_strict_mode lässt PHP nur Kennungen annehmen, die es selbst vergeben hat.
session.name = __Host-sitzung
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = "Lax"
session.use_strict_mode = 1
Eigene Cookies setzt du mit setcookie und einer Liste von Optionen. Gib path immer an, sonst gilt nur das aktuelle Verzeichnis; seit PHP 8.5 gibt es dort auch partitioned.
setcookie('sprache', 'de', ['expires' => time() + 31536000, 'path' => '/', 'secure' => true, 'samesite' => 'Lax']);
Express
Bei express-session ist HttpOnly schon an, Secure und SameSite nicht, und der Name lautet sonst connect.sid. Beendet ein Proxy davor HTTPS, braucht Express trust proxy, sonst setzt es das Secure-Cookie gar nicht.
app.set('trust proxy', 1) // nur hinter einem HTTPS-Proxy
app.use(session({
name: '__Host-sid',
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { path: '/', secure: true, httpOnly: true, sameSite: 'lax' },
}))
Django
Beim Sitzungs-Cookie setzt Django HttpOnly, SameSite=Lax, Pfad / und keine Domain selbst, Secure nicht; python manage.py check --deploy warnt, solange es fehlt. Von Haus aus lebt das Cookie zwei Wochen; mit SESSION_EXPIRE_AT_BROWSER_CLOSE endet es mit dem Browser.
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_NAME = '__Host-sessionid'
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
WordPress
WordPress setzt seine Anmelde-Cookies selbst: mit HttpOnly, ohne SameSite und mit Secure nur, wenn es die Verbindung als HTTPS erkennt. Hinter einem Proxy, der HTTPS beendet, braucht es dafür einen Eintrag in wp-config.php, der X-Forwarded-Proto auswertet; die WordPress-Dokumentation zeigt ihn.
Was du siehst
- In der Cookie-Tabelle HttpOnly und Secure angehakt (im deutschen Chrome heißt Secure „Sicher“, Firefox zeigt „true“), „Lax“ unter SameSite und als Ablauf des Anmelde-Cookies „Sitzung“, in Firefox „Sitzungsende“.
- In der Konsole fehlt das Anmelde-Cookie in document.cookie; das bewirkt HttpOnly.
- In Chrome unter „Netzwerk“ › Anfrage der Anmeldung › Reiter „Cookies“ die „Antwort-Cookies“; ein verworfenes ist markiert, sein Info-Symbol nennt den Grund.
- In der Werkstatt unter „Cookies“ den Befund „Schutzattribute der Cookies“ mit „Kriterium erfüllt“ und einem Beleg wie „Cookie 1 (__Host-) [Sitzung vermutet]: Secure, HttpOnly, SameSite=Lax. Namen und Werte entfernt.“
Wenn etwas nicht passt
- Das Cookie fehlt, seit es Secure trägt, oder WordPress setzt es ohne Secure: Die Seite kam über HTTP, oder die Anwendung hinter einem Proxy hält die Verbindung für unverschlüsselt — siehe Schritt 6 zu Express und WordPress.
- Ein __Host-Cookie erscheint nicht: Es hat einen Domain-Eintrag, oder ihm fehlt Secure oder Path=/, in PHP etwa bei setcookie ohne path.
- Besucher wirken nach einem Link von außen abgemeldet: Das Anmelde-Cookie steht auf Strict. Nimm Lax.
- Die Anmeldung über einen fremden Anbieter oder die Rückkehr vom Zahlungsdienst bricht ab: Dieser Schritt kommt oft als POST-Formular der fremden Seite, bei dem Lax das Cookie zurückhält. Gib nur dem kurzlebigen Übergabe-Cookie SameSite=None mit Secure, nicht dem Anmelde-Cookie.
- Die Werkstatt zeigt überall „Unklar“: Du hast eine Weiterleitung eingefügt, etwa die Antwort der Anmeldung mit 302 oder 303; die wertet sie nicht aus. Füge dann nur deren Set-Cookie-Zeilen ein und übergeh die Meldungen zu fehlenden Headern.
- Die Werkstatt meldet Djangos Cookie csrftoken als vermutete Sitzung ohne HttpOnly: Sie schätzt am Namen, und „token“ zählt dazu. Laut Django bringt HttpOnly dort keinen praktischen Schutz; diesen Hinweis kannst du übergehen.
So kehrst du zurück
Spiele die gesicherte Konfiguration zurück; die Attribute ändern sich mit der nächsten Set-Cookie-Zeile. Ein umbenanntes Cookie liest der Server nicht mehr: Alle Angemeldeten müssen sich einmal neu anmelden, beim Umstieg wie beim Zurückgehen. Alte Cookies löschst du unter ihrem alten Namen wie bei der Abmeldung (Schritt 4).
So prüfst du das Ergebnis
- Melde dich ab und wieder an und vergleiche Cookie-Tabelle und document.cookie mit „Was du siehst“.
- Kopiere die Set-Cookie-Zeilen der Anmeldung und einer gewöhnlichen Seite, wie in Antwort-Header richtig kopieren beschrieben. Ersetze nur die Werte durch drei Punkte; die Namen braucht die Werkstatt für Präfix und Anmelde-Verdacht und verwirft sie danach.
- Wähle in der Werkstatt „Die Antwort stammt von HTTPS“ und klicke auf „Header auswerten“. Wie du Befunde liest, steht in Sicherheitsbefunde richtig lesen.
- Spiele die Abläufe aus den Voraussetzungen erneut durch, besonders Link von außen, fremde Anmeldung und Abmeldung.
Was dieser Artikel nicht sagt
- Die Werkstatt sieht nur die eingefügten Set-Cookie-Zeilen, keine Cookies aus Skripten oder fremden Diensten. Ob ein Cookie eine Anmeldung trägt, schätzt sie am Namen; heißt es anders, wie bei WordPress, prüft sie dort weder HttpOnly noch SameSite. Laufzeit und die Präfixe __Http- und __Host-Http- bewertet sie nicht eigens.
- Die Attribute schützen das Cookie auf dem Weg und im Browser. Eingeschleustes Skript (Cross-Site-Scripting (XSS)) kann trotzdem im Namen des Besuchers handeln, und die Attribute ersetzen weder CSRF-Schutz noch eine sichere Sitzungsverwaltung auf dem Server.
- Ob du für ein Cookie eine Einwilligung brauchst, regelt § 25 TDDDG. Die Liste aus Schritt 1 hilft dabei, ersetzt aber keine rechtliche Prüfung.
- Die Cookie-Regeln der IETF sind noch ein Entwurf vor der Veröffentlichung als RFC.
Weiter
Die Set-Cookie-Zeilen deiner Anmeldung in der Werkstatt auswerten →Passende Artikel
Begriffe dazu
Quellen
Geprüft am 3. Oktober 2026. Die Einordnung ist eine fachliche Bewertung, keine Rechtsberatung. Einen Fehler gefunden? Die Kontaktdaten stehen im Impressum.