Richtiger Weg, um Cookies serverseitig zu löschen

141

Für meinen Authentifizierungsprozess erstelle ich ein eindeutiges Token, wenn sich ein Benutzer anmeldet, und füge dieses in ein Cookie ein, das zur Authentifizierung verwendet wird.

Also würde ich so etwas vom Server senden:

Set-Cookie: token=$2a$12$T94df7ArHkpkX7RGYndcq.fKU.oRlkVLOkCBNrMilaSWnTcWtCfJC; path=/;

Welches funktioniert auf allen Browsern. Um dann ein Cookie zu löschen, sende ich ein ähnliches Cookie mit dem expiresfür den 1. Januar 1970 festgelegten Feld

Set-Cookie: token=$2a$12$T94df7ArHkpkX7RGYndcq.fKU.oRlkVLOkCBNrMilaSWnTcWtCfJC; path=/; expires=Thu, Jan 01 1970 00:00:00 UTC; 

Und das funktioniert gut in Firefox, löscht aber das Cookie in IE oder Safari nicht.

Was ist der beste Weg, um ein Cookie zu löschen (vorzugsweise ohne JavaScript)? Die Methode "Set-the-Expires-in-the-Past" scheint sperrig zu sein. Und warum funktioniert das auch in FF, aber nicht in IE oder Safari?

Joshkunz
quelle
Siehe auch stackoverflow.com/a/20320610/212378
Alexis Wilke

Antworten:

208

Wenn Sie denselben Cookie-Wert mit ; expiresangehängtem senden, wird das Cookie nicht zerstört.

Machen Sie das Cookie ungültig, indem Sie einen leeren Wert festlegen und auch ein expiresFeld einfügen:

Set-Cookie: token=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT

Beachten Sie, dass Sie nicht alle Browser zwingen können, ein Cookie zu löschen. Der Client kann den Browser so konfigurieren, dass das Cookie auch dann bestehen bleibt, wenn es abgelaufen ist. Das Einstellen des Werts wie oben beschrieben würde dieses Problem lösen.

Lekensteyn
quelle
52
Ich würde empfehlen, einen leeren Text als Müll zu verwenden, anstatt "deleted"später Verwechslungen mit einem potenziell legalen Wert zu vermeiden, der gleich "gelöscht" ist
yegor256
8
@raulk Ja, du bist richtig. Komisch, dass es vorher nicht bemerkt wurde, hoffentlich hat es nicht zu viele Probleme verursacht. yegor256 sollte in den meisten Fällen ein leerer Wert funktionieren. Verwandte: Einige Leute fragen sich vielleicht, warum ihre Cookies auch nach dem Senden dieses Headers nicht entfernt werden. Schauen Sie sich in diesem Fall Cookies aus anderen Domains an. Nach dem Löschen foo=bar; domain=www.example.comwird beispielsweise ein anderes Cookie foo=qux; domain=.example.comverwendet.
Lekensteyn
3
"Der Client kann den Browser so konfigurieren, dass das Cookie auch dann bestehen bleibt, wenn es abgelaufen ist. Das Festlegen des oben beschriebenen Werts würde dieses Problem lösen." Konnte der Client den Browser nicht so konfigurieren, dass Ihre Anfrage ignoriert wird, den Cookie-Inhalt ebenfalls auf "gelöscht" zu setzen? Sie haben keine Möglichkeit, den Client zu zwingen, etwas zu tun, was er nicht möchte.
Ajedi32
@ Ajedi32 Es könnte sein, aber dann müssen Sie zusätzliche Anstrengungen unternehmen, um dies zu tun (als Kunde). Das Verhalten beim Ignorieren eines leeren Werts ist weitaus häufiger. Es wäre für einen Browser nicht sinnvoll, solche Anforderungen zu ignorieren, insbesondere bei ungültigen Sitzungs-IDs.
Lekensteyn
2
-1, weil ich noch nie eine Möglichkeit gesehen habe, einen Browser so zu konfigurieren, dass das Ablaufen von Cookies ignoriert wird, und nicht davon überzeugt bin, dass ein Browser vorhanden ist, der eine solche Option bietet. Darüber hinaus ist der erste Satz Ihrer Antwort nach der ziemlich kühnen Bearbeitung von @ DaveJarvis für jeden großen Browser oder jeden spezifikationskonformen Benutzeragenten völlig falsch. tools.ietf.org/search/rfc6265#section-5.3 schreibt vor, dass "der Benutzeragent alle abgelaufenen Cookies aus dem Cookie-Speicher entfernen MUSS, wenn zu irgendeinem Zeitpunkt ein abgelaufenes Cookie im Cookie-Speicher vorhanden ist." und nach meinem besten Wissen ist es das, was jeder Browser tatsächlich tut.
Mark Amery
46

Zum Zeitpunkt des Schreibens dieser Antwort scheint die akzeptierte Antwort auf diese Frage zu besagen, dass Browser kein Cookie löschen müssen, wenn sie ein Ersatz-Cookie erhalten, dessen ExpiresWert in der Vergangenheit liegt. Diese Behauptung ist falsch. Die Einstellung Expires, in der Vergangenheit zu sein, ist die standardmäßige, spezifikationskonforme Methode zum Löschen eines Cookies. Benutzeragenten müssen diese spezifizieren.

Die Verwendung eines ExpiresAttributs in der Vergangenheit zum Löschen eines Cookies ist korrekt und dient zum Entfernen von Cookies, die von der Spezifikation vorgegeben werden. Im Beispielabschnitt von RFC 6255 heißt es:

Um ein Cookie zu entfernen, gibt der Server einen Set-Cookie-Header mit einem Ablaufdatum in der Vergangenheit zurück. Der Server kann das Cookie nur dann erfolgreich entfernen, wenn der Pfad und das Domain-Attribut im Set-Cookie-Header mit den Werten übereinstimmen, die beim Erstellen des Cookies verwendet wurden.

Der Abschnitt Anforderungen an Benutzeragenten enthält die folgenden Anforderungen, die zusammen dazu führen, dass ein Cookie sofort gelöscht werden muss, wenn der Benutzeragent ein neues Cookie mit demselben Namen erhält, dessen Ablaufdatum in der Vergangenheit liegt

  1. Wenn [beim Empfang eines neuen Cookies] der Cookie-Speicher ein Cookie mit demselben Namen, derselben Domäne und demselben Pfad wie das neu erstellte Cookie enthält:

    1. ...
    2. ...
    3. Aktualisieren Sie die Erstellungszeit des neu erstellten Cookies so, dass sie mit der Erstellungszeit des alten Cookies übereinstimmt.
    4. Entfernen Sie den alten Keks aus dem Keksladen.
  2. Fügen Sie das neu erstellte Cookie in den Cookie-Store ein.

Ein Cookie ist "abgelaufen", wenn das Cookie in der Vergangenheit ein Ablaufdatum hat.

Der Benutzeragent MUSS alle abgelaufenen Cookies aus dem Cookie-Speicher entfernen, wenn zu irgendeinem Zeitpunkt ein abgelaufenes Cookie im Cookie-Speicher vorhanden ist.

Die obigen Punkte 11-3, 11-4 und 12 bedeuten zusammen, dass beim Empfang eines neuen Cookies mit demselben Namen, derselben Domäne und demselben Pfad das alte Cookie gelöscht und durch das neue Cookie ersetzt werden muss. Schließlich schreibt der folgende Punkt über abgelaufene Cookies weiter vor, dass das neue Cookie danach auch sofort gelöscht werden muss. Die Spezifikation bietet Browsern in diesem Punkt keinen Spielraum. Wenn ein Browser dem Benutzer die Option bietet, den Ablauf von Cookies zu deaktivieren, wie aus der akzeptierten Antwort hervorgeht, dass dies bei einigen Browsern der Fall ist, verstößt dies gegen die Spezifikation. (Eine solche Funktion hätte auch wenig Sinn und ist meines Wissens in keinem Browser vorhanden.)

Warum hat das OP dieser Frage dann beobachtet, dass dieser Ansatz fehlgeschlagen ist? Obwohl ich eine Kopie von Internet Explorer nicht abgestaubt habe, um das Verhalten zu überprüfen, vermute ich, dass dies daran lag, dass der ExpiresWert des OP fehlerhaft war! Sie haben diesen Wert verwendet:

expires=Thu, Jan 01 1970 00:00:00 UTC;

Dies ist jedoch in zweierlei Hinsicht syntaktisch ungültig.

Der Syntaxabschnitt der Spezifikation schreibt vor, dass der Wert des ExpiresAttributs a sein muss

rfc1123 -date, definiert in [RFC2616], Abschnitt 3.3.1

Nach dem zweiten Link oben finden wir dies als Beispiel für das Format:

Sun, 06 Nov 1994 08:49:37 GMT

und finde, dass die Syntaxdefinition ...

  1. erfordert, dass die Daten im Format Tag Monat Jahr geschrieben werden, nicht im Format Monat Tag Jahr Jahr , wie es vom Fragesteller verwendet wird.

    Insbesondere definiert es rfc1123-datewie folgt:

    rfc1123-date = wkday "," SP date1 SP time SP "GMT"
    

    und definiert date1wie folgt:

    date1        = 2DIGIT SP month SP 4DIGIT
                 ; day month year (e.g., 02 Jun 1982)
    

und

  1. erlaubt nicht UTCals Zeitzone.

    Die Spezifikation enthält die folgende Aussage darüber, welche Zeitzonenversätze in diesem Format zulässig sind:

    Alle HTTP-Datums- / Zeitstempel MÜSSEN ausnahmslos in Greenwich Mean Time (GMT) dargestellt werden.

    Wenn wir uns eingehender mit der ursprünglichen Spezifikation dieses Datetime-Formats befassen, stellen wir fest, dass in der ursprünglichen Spezifikation unter https://tools.ietf.org/html/rfc822 im Abschnitt Syntax "UT" (was "Universalzeit" bedeutet) aufgeführt ist. ) als möglicher Wert, listet jedoch nicht UTC (Coordinated Universal Time) als gültig auf. Soweit ich weiß, war die Verwendung von "UTC" in diesem Datumsformat nie gültig. es war kein gültiger Wert , wenn das Format erst im Jahr 1982 festgelegt wurde, und die HTTP - Spezifikation hat eine streng angenommen mehr restriktive Version des Formats durch das Verbot der Verwendung alles „Zone“ anderer Werte als „GMT“.

Wenn der Fragesteller hier stattdessen ein ExpiresAttribut wie dieses verwendet hat , dann:

expires=Thu, 01 Jan 1970 00:00:00 GMT;

dann hätte es vermutlich geklappt.

Mark Amery
quelle
15

Das Setzen von "läuft ab" auf ein vergangenes Datum ist die Standardmethode zum Löschen eines Cookies.

Ihr Problem liegt wahrscheinlich daran, dass das Datumsformat nicht konventionell ist. IE erwartet wahrscheinlich nur GMT.

unwiderlegbar
quelle
2

Verwenden Sie Max-Age = -1 anstelle von "Expires". Die Syntax ist kürzer, weniger wählerisch, und Max-Age hat ohnehin Vorrang vor Expires.

Steven Pemberton
quelle
-1

Für die JAF-RS-Implementierung von GlassFish Jersey habe ich dieses Problem behoben, indem alle gängigen Parameter beschrieben werden. Mindestens drei der Parameter müssen gleich sein: Name (= "Name"), Pfad (= "/") und Domäne (= Null):

public static NewCookie createDomainCookie(String value, int maxAgeInMinutes) {
    ZonedDateTime time = ZonedDateTime.now().plusMinutes(maxAgeInMinutes);
    Date expiry = time.toInstant().toEpochMilli();
    NewCookie newCookie = new NewCookie("name", value, "/", null, Cookie.DEFAULT_VERSION,null, maxAgeInMinutes*60, expiry, false, false);
    return newCookie;
}

Und verwenden Sie es auf die übliche Weise, um Cookies zu setzen:

NewCookie domainNewCookie = RsCookieHelper.createDomainCookie(token, 60);
Response res = Response.status(Response.Status.OK).cookie(domainNewCookie).build();

und um den Cookie zu löschen:

NewCookie domainNewCookie = RsCookieHelper.createDomainCookie("", 0);
Response res = Response.status(Response.Status.OK).cookie(domainNewCookie).build();
RoutesMaps.com
quelle
Wenn ich maxAge auf 0 setze, wird für mich ein Cookie mit Max-Age = 0 ausgegeben, das Chrome zu ignorieren scheint. In Abschnitt 4.1.1 von RFC 6265 wird die Syntax von Max-Age als "nicht nullstellig" angegeben. Das könnte der Grund sein. Wie in @ JoshC13 erwähnt, geht es in Abschnitt 5.2.2 jedoch um die Interpretation von Werten kleiner oder gleich Null. Also widerspricht es sich dort irgendwie ...
Matthijs Wessels
Ich kenne keine Details, aber diese paarweisen Werte funktionieren wirklich in Chrome und anderen Browsern: maxAgeInMinutes * 60, Ablaufdatum.
RoutesMaps.com
1
@MatthijsWessels Guter Fang! Ich habe etwas tiefer gegraben, und der offensichtliche Widerspruch ist tatsächlich beabsichtigt, wie in den Errata unter rfc-editor.org/errata/eid3430 vermerkt . Um die Interoperabilität zu maximieren, müssen Benutzeragenten eine Null oder ein Negativ Max-Ageals das früheste darstellbare Datum und die früheste darstellbare Uhrzeit interpretieren. Servern ist es jedoch untersagt, einen solchen Max-AgeWert zu senden . Ich denke, die Autoren wussten sowohl von vorhandenen Clients, die nicht damit umgehen konnten, Max-Age=0als auch von Servern, die sie zum Zeitpunkt des Schreibens der Spezifikation gesendet hatten, und versuchten, das Problem von beiden Seiten zu lösen.
Mark Amery
@ Crimean.us Ich kann auch nicht mehr repro. Vielleicht habe ich etwas falsch gemacht
Matthijs Wessels
@MatthijsWessels Das Problem mit dem Ignorieren von Max-Age = 0 wurde in meinem Beispiel behoben, indem das Ablaufdatum auf ZonedDateTime.now (). PlusMinutes (maxAgeInMinutes) gesetzt wurde. Für maxAgeInMinutes = 0 ist dies die aktuelle Datums- / Uhrzeitangabe. Dieser Code funktioniert lange in der realen Webanwendung.
RoutesMaps.com