Modo corretto per eliminare i cookie lato server


141

Per il mio processo di autenticazione creo un token univoco quando un utente accede e lo inserisco in un cookie utilizzato per l'autenticazione.

Quindi vorrei inviare qualcosa del genere dal server:

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

Che funziona su tutti i browser. Quindi per eliminare un cookie invio un cookie simile con il expirescampo impostato per il 1 gennaio 1970

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

E questo funziona bene su Firefox ma non elimina i cookie su IE o Safari.

Qual è il modo migliore per eliminare un cookie (preferibilmente senza JavaScript)? Il metodo set-the-expires-in-the-past sembra ingombrante. E anche perché funziona in FF ma non in IE o Safari?


Risposte:


209

L'invio dello stesso valore di cookie con l' ; expiresaggiunta non distruggerà il cookie.

Invalida il cookie impostando un valore vuoto e includi anche un expirescampo:

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

Si noti che non è possibile forzare tutti i browser a eliminare un cookie. Il client può configurare il browser in modo tale che il cookie persista, anche se è scaduto. L'impostazione del valore come descritto sopra risolverebbe questo problema.


52
Consiglierei di usare un testo vuoto come spazzatura, invece di "deleted", per evitare confusione in seguito con un valore potenzialmente legale uguale a "cancellato"
yegor256

8
@raulk Sì, hai ragione. Divertente che non sia stato notato prima, si spera che non abbia causato troppi problemi. yegor256, un valore vuoto dovrebbe funzionare nella maggior parte dei casi. Correlati: alcune persone potrebbero chiedersi perché i loro cookie non vengano rimossi anche dopo aver inviato questa intestazione. In tal caso, dai un'occhiata ai cookie di altri domini. Ad esempio, dopo l'eliminazione foo=bar; domain=www.example.com, foo=qux; domain=.example.comverrà utilizzato un altro cookie .
Lekensteyn,

3
"Il client può configurare il browser in modo tale che il cookie persista, anche se è scaduto. L'impostazione del valore come descritto sopra risolverebbe questo problema." Il client non potrebbe configurare il browser in modo da ignorare la tua richiesta di impostare anche il contenuto dei cookie su "eliminato"? Non hai modo di forzare il cliente a fare tutto ciò che non vuole.
Ajedi32,

@ Ajedi32 Potrebbe, ma poi devi compiere ulteriori sforzi per farlo (come client). Il comportamento di ignorare un valore vuoto è molto più comune, non avrebbe senso per un browser ignorare tali richieste, specialmente per gli ID di sessione che sono invalidati.
Lekensteyn,

2
-1 perché non ho mai visto un modo per configurare un browser in modo da ignorare la scadenza dei cookie e non sono convinto che esista un browser che offra tale opzione. Inoltre, la prima frase della tua risposta, dopo la modifica piuttosto audace di @ DaveJarvis, è ora completamente falsa per qualsiasi browser principale o qualsiasi agente utente conforme alle specifiche. tools.ietf.org/search/rfc6265#section-5.3 impone che "L'agente utente DEVE eliminare tutti i cookie scaduti dall'archivio cookie se, in qualsiasi momento, esiste un cookie scaduto nell'archivio cookie." e per quanto ne so, questo è ciò che fa effettivamente ogni browser.
Mark Amery,

47

Al momento in cui scrivo questa risposta, la risposta accettata a questa domanda sembra affermare che i browser non sono tenuti ad eliminare un cookie quando ricevono un cookie sostitutivo il cui Expiresvalore è in passato. Tale affermazione è falsa. L'impostazione Expiresdi essere in passato è il modo standard e conforme alle specifiche di eliminare un cookie e gli agenti utente sono tenuti dalle specifiche a rispettarlo.

L'uso di un Expiresattributo in passato per eliminare un cookie è corretto ed è il modo per rimuovere i cookie dettati dalle specifiche. La sezione degli esempi di RFC 6255 afferma:

Infine, per rimuovere un cookie, il server restituisce un'intestazione Set-Cookie con una data di scadenza nel passato. Il server riuscirà a rimuovere il cookie solo se l'attributo Path e Domain nell'intestazione Set-Cookie corrispondono ai valori utilizzati al momento della creazione del cookie.

La sezione Requisiti agente utente include i seguenti requisiti, che insieme hanno l'effetto di eliminare immediatamente un cookie se l'agente utente riceve un nuovo cookie con lo stesso nome la cui data di scadenza è passata

  1. Se [quando riceve un nuovo cookie] l'archivio cookie contiene un cookie con lo stesso nome, dominio e percorso del cookie appena creato:

    1. ...
    2. ...
    3. Aggiorna l'ora di creazione del cookie appena creato in modo che corrisponda all'ora di creazione del cookie precedente.
    4. Rimuovi il vecchio cookie dal cookie store.
  2. Inserisci il cookie appena creato nel cookie store.

Un cookie è "scaduto" se il cookie ha una data di scadenza in passato.

L'agente utente DEVE eliminare tutti i cookie scaduti dal negozio di cookie se, in qualsiasi momento, esiste un cookie scaduto nel negozio di cookie.

I punti 11-3, 11-4 e 12 sopra indicano che quando un nuovo cookie viene ricevuto con lo stesso nome, dominio e percorso, il vecchio cookie deve essere espulso e sostituito con il nuovo cookie. Infine, il punto di sotto di circa cookie scaduti ulteriori dettami che, dopo che è fatto, il nuovo biscotto deve anche essere immediatamente sfrattato. Le specifiche non offrono spazio di manovra ai browser su questo punto; se un browser offrisse all'utente la possibilità di disabilitare la scadenza dei cookie, come suggerisce la risposta accettata da alcuni browser, ciò violerebbe le specifiche. (Una funzione del genere sarebbe inoltre poco utile e, per quanto ne so, non esiste in nessun browser.)

Perché, quindi, l'OP di questa domanda ha riscontrato un fallimento di questo approccio? Anche se non ho rispolverato una copia di Internet Explorer per verificarne il comportamento, sospetto che ciò sia dovuto al fatto che il Expiresvalore del PO non era corretto! Hanno usato questo valore:

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

Tuttavia, questo è sintatticamente non valido in due modi.

La sezione della sintassi della specifica indica che il valore Expiresdell'attributo deve essere a

rfc1123 -date, definito in [RFC2616], Sezione 3.3.1

Seguendo il secondo link sopra, troviamo questo dato come esempio del formato:

Sun, 06 Nov 1994 08:49:37 GMT

e scopri che la definizione della sintassi ...

  1. richiede che le date siano scritte nel formato giorno mese anno , non nel formato anno mese giorno utilizzato dall'interrogatore della domanda.

    In particolare, definisce rfc1123-datecome segue:

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

    e definisce date1così:

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

e

  1. non consente UTCcome fuso orario.

    La specifica contiene la seguente dichiarazione su quali offset del fuso orario sono accettabili in questo formato:

    Tutti i timbri data / ora HTTP DEVONO essere rappresentati in GMT (Greenwich Mean Time), senza eccezioni.

    Inoltre, se approfondiamo le specifiche originali di questo formato datetime, scopriamo che nelle specifiche iniziali in https://tools.ietf.org/html/rfc822 , la sezione Sintassi elenca "UT" (che significa "tempo universale" ) come valore possibile, ma non elenca UTC (Coordinated Universal Time) come valido. Per quanto ne so, l'uso di "UTC" in questo formato data non è mai stato valido; non era un valore valido quando il formato è stato specificato per la prima volta nel 1982 e le specifiche HTTP hanno adottato una versione strettamente più restrittiva del formato vietando l'uso di tutti i valori "zone" diversi da "GMT".

Se la domanda qui posta aveva invece usato un Expiresattributo come questo , allora:

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

quindi avrebbe presumibilmente funzionato.


15

L'impostazione "scade" su una data passata è il modo standard per eliminare un cookie.

Il tuo problema è probabilmente perché il formato della data non è convenzionale. Probabilmente IE si aspetta solo GMT.


2

Usa Max-Age = -1 anziché "Scadenza". È più breve, meno esigente riguardo alla sintassi e Max-Age ha comunque la precedenza su Scadenza.


-1

Per l'implementazione di GlassFish Jersey JAX-RS ho risolto questo problema con un metodo comune che descrive tutti i parametri comuni. Almeno tre dei parametri devono essere uguali: nome (= "nome"), percorso (= "/") e dominio (= 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;
}

E usalo nel modo comune per impostare i cookie:

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

e per eliminare il cookie:

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

per me quando imposto maxAge su 0, genera un cookie con Max-Age = 0 che Chrome sembra ignorare. Nella sezione 4.1.1 di RFC 6265 specifica la sintassi di Max-Age come "non-zero-digit". Questo potrebbe essere il motivo. Sebbene, come menzionato da @ JoshC13, la sezione 5.2.2 parli dell'interpretazione di valori inferiori o uguali a zero. Quindi in qualche modo si contraddice lì ...
Matthijs Wessels il

Non conosco i dettagli, ma questi valori in coppia funzionano davvero in Chrome e altri browser: maxAgeInMinutes * 60, scadenza.
RoutesMaps.com

1
@MatthijsWessels Buona cattura! Ho scavato un po 'più a fondo, e l'apparente contraddizione è in realtà intenzionale, come notato nell'errata su rfc-editor.org/errata/eid3430 . Per "interoperabilità ingrandimento", gli interpreti sono tenuti a interpretare uno zero o negativa Max-Agecome la data e l'ora rappresentabili prima, ma i server sono vietati da l'invio di un tale Max-Agevalore. Immagino che gli autori fossero a conoscenza sia dei client esistenti che non potevano gestire, Max-Age=0sia dei server che lo hanno inviato nel momento in cui hanno scritto le specifiche, e hanno cercato di mitigare il problema da entrambe le parti.
Mark Amery,

@ Crimean.us Non riesco più a riproporre. Forse ho fatto qualcosa di sbagliato
Matthijs Wessels il

@MatthijsWessels Il problema con ignora Max-Age = 0 è stato corretto nel mio esempio impostando la data di scadenza su ZonedDateTime.now (). PlusMinutes (maxAgeInMinutes). Per maxAgeInMinutes = 0 è il datetime corrente. Questo codice funziona da molto tempo nella vera applicazione web.
RoutesMaps.com il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.