Bonne façon de supprimer les cookies côté serveur

141

Pour mon processus d'authentification, je crée un jeton unique lorsqu'un utilisateur se connecte et je le place dans un cookie qui est utilisé pour l'authentification.

Donc, j'enverrais quelque chose comme ça depuis le serveur:

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

Ce qui fonctionne sur tous les navigateurs. Ensuite, pour supprimer un cookie, j'envoie un cookie similaire avec le expireschamp défini pour le 1er janvier 1970

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

Et cela fonctionne bien sur Firefox mais ne supprime pas le cookie sur IE ou Safari.

Alors, quelle est la meilleure façon de supprimer un cookie (sans JavaScript de préférence)? La méthode du "set-the-expires-in-the-past" semble volumineuse. Et aussi pourquoi cela fonctionne-t-il dans FF mais pas dans IE ou Safari?

Joshkunz
la source
Voir aussi stackoverflow.com/a/20320610/212378
Alexis Wilke

Réponses:

209

L'envoi de la même valeur de cookie avec l' ; expiresajout ne détruira pas le cookie.

Invalidez le cookie en définissant une valeur vide et incluez également un expireschamp:

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

Notez que vous ne pouvez pas forcer tous les navigateurs à supprimer un cookie. Le client peut configurer le navigateur de manière à ce que le cookie persiste, même s'il a expiré. Définir la valeur comme décrit ci-dessus résoudrait ce problème.

Lekensteyn
la source
52
Je recommanderais d'utiliser un texte vide comme des déchets, au lieu de "deleted", pour éviter toute confusion plus tard avec une valeur potentiellement légale égale à "supprimé"
yegor256
8
@raulk Oui, vous avez raison. C'est drôle que cela n'ait pas été remarqué auparavant, j'espère que cela n'a pas causé trop de problèmes. yegor256, une valeur vide devrait fonctionner dans la plupart des cas. Connexes: certaines personnes peuvent se demander pourquoi leurs cookies ne sont pas supprimés même après l'envoi de cet en-tête. Dans ce cas, jetez un œil aux cookies d'autres domaines. Par exemple, après la suppression foo=bar; domain=www.example.com, un autre cookie foo=qux; domain=.example.comsera utilisé.
Lekensteyn
3
"Le client peut configurer le navigateur de telle manière que le cookie persiste, même s'il a expiré. Définir la valeur comme décrit ci-dessus résoudrait ce problème." Le client n'a-t-il pas pu configurer le navigateur pour ignorer votre demande de définir le contenu du cookie sur "supprimé" également? Vous n'avez aucun moyen de forcer le client à faire ce qu'il ne veut pas.
Ajedi32
@ Ajedi32 Cela pourrait, mais vous devez alors faire des efforts supplémentaires pour le faire (en tant que client). Le comportement consistant à ignorer une valeur vide est beaucoup plus courant, il ne serait pas logique pour un navigateur d'ignorer de telles demandes, en particulier pour les identifiants de session qui sont invalidés.
Lekensteyn
2
-1 parce que je n'ai jamais vu un moyen de configurer un navigateur pour ignorer l'expiration des cookies, et je ne suis pas convaincu qu'il existe un navigateur offrant une telle option. De plus, la première phrase de votre réponse, après la modification plutôt audacieuse de @ DaveJarvis, est maintenant carrément fausse pour tout navigateur majeur ou tout agent utilisateur conforme aux spécifications. tools.ietf.org/search/rfc6265#section-5.3 stipule que "L'agent utilisateur DOIT expulser tous les cookies expirés du magasin de cookies si, à tout moment, un cookie expiré existe dans le magasin de cookies." et au meilleur de ma connaissance, c'est ce que fait chaque navigateur.
Mark Amery
47

Au moment où j'écris cette réponse, la réponse acceptée à cette question semble indiquer que les navigateurs ne sont pas tenus de supprimer un cookie lorsqu'ils reçoivent un cookie de remplacement dont la Expiresvaleur est dans le passé. Cette affirmation est fausse. Le fait Expiresd'être dans le passé est le moyen standard et conforme aux spécifications de supprimer un cookie, et les agents utilisateurs sont tenus par la spécification de le respecter.

L'utilisation d'un Expiresattribut dans le passé pour supprimer un cookie est correcte et constitue le moyen de supprimer les cookies dicté par la spécification. La section des exemples de la RFC 6255 indique:

Enfin, pour supprimer un cookie, le serveur renvoie un en-tête Set-Cookie avec une date d'expiration dans le passé. Le serveur réussira à supprimer le cookie uniquement si l'attribut Chemin et domaine dans l'en-tête Set-Cookie correspond aux valeurs utilisées lors de la création du cookie.

La section Exigences de l'agent utilisateur comprend les exigences suivantes, qui, ensemble, ont pour effet qu'un cookie doit être immédiatement effacé si l'agent utilisateur reçoit un nouveau cookie avec le même nom dont la date d'expiration est dans le passé

  1. Si [lors de la réception d'un nouveau cookie], le magasin de cookies contient un cookie avec le même nom, domaine et chemin que le cookie nouvellement créé:

    1. ...
    2. ...
    3. Mettez à jour l'heure de création du cookie nouvellement créé pour correspondre à l'heure de création de l'ancien cookie.
    4. Supprimez l'ancien cookie du magasin de cookies.
  2. Insérez le cookie nouvellement créé dans le magasin de cookies.

Un cookie est "expiré" si le cookie a une date d'expiration dans le passé.

L'agent utilisateur DOIT expulser tous les cookies expirés du magasin de cookies si, à tout moment, un cookie expiré existe dans le magasin de cookies.

Les points 11-3, 11-4 et 12 ci-dessus signifient ensemble que lorsqu'un nouveau cookie est reçu avec le même nom, domaine et chemin, l'ancien cookie doit être effacé et remplacé par le nouveau cookie. Enfin, le point ci-dessous sur les cookies expirés indique en outre qu'après cela, le nouveau cookie doit également être immédiatement expulsé. La spécification n'offre aucune marge de manœuvre aux navigateurs sur ce point; si un navigateur offrait à l'utilisateur la possibilité de désactiver l'expiration des cookies, comme le suggère la réponse acceptée par certains navigateurs, alors ce serait en violation des spécifications. (Une telle fonctionnalité aurait également peu d'utilité, et pour autant que je sache, elle n'existe dans aucun navigateur.)

Pourquoi, alors, le PO de cette question a-t-il vu cette approche échouer? Bien que je n'ai pas dépoussiéré une copie d'Internet Explorer pour vérifier son comportement, je soupçonne que c'était parce que la Expiresvaleur de l'OP était mal formée! Ils ont utilisé cette valeur:

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

Cependant, cela est syntaxiquement invalide de deux manières.

La section de syntaxe de la spécification stipule que la valeur de l' Expiresattribut doit être un

rfc1123 -date, défini dans la [RFC2616], section 3.3.1

En suivant le deuxième lien ci-dessus, nous trouvons ceci donné à titre d'exemple de format:

Sun, 06 Nov 1994 08:49:37 GMT

et constatez que la définition de syntaxe ...

  1. exige que les dates soient écrites au format jour mois année , et non au format mois jour année tel qu'utilisé par le demandeur.

    Plus précisément, il définit rfc1123-datecomme suit:

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

    et définit date1comme ceci:

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

et

  1. ne permet pas UTCcomme fuseau horaire.

    La spécification contient la déclaration suivante sur les décalages de fuseau horaire acceptables dans ce format:

    Tous les horodatages HTTP DOIVENT être représentés en heure moyenne de Greenwich (GMT), sans exception.

    De plus, si nous approfondissons la spécification originale de ce format datetime, nous trouvons que dans sa spécification initiale dans https://tools.ietf.org/html/rfc822 , la section Syntaxe répertorie "UT" (signifiant "temps universel" ) comme valeur possible, mais ne pas la liste non UTC (temps universel coordonné) comme valide. Autant que je sache, utiliser "UTC" dans ce format de date n'a jamais été valide; ce n'était pas une valeur valide lorsque le format a été spécifié pour la première fois en 1982, et la spécification HTTP a adopté une version strictement plus restrictive du format en interdisant l'utilisation de toutes les valeurs de "zone" autres que "GMT".

Si le demandeur de question ici avait utilisé à la place un Expiresattribut comme celui-ci , alors:

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

alors cela aurait probablement fonctionné.

Mark Amery
la source
15

Définir «expire» sur une date passée est la méthode standard pour supprimer un cookie.

Votre problème est probablement dû au fait que le format de la date n'est pas conventionnel. IE attend probablement GMT uniquement.

irréprochable
la source
2

Utilisez Max-Age = -1 plutôt que "Expire". Il est plus court, moins pointilleux sur la syntaxe et Max-Age a de toute façon la priorité sur Expires.

Steven Pemberton
la source
-1

Pour la mise en œuvre de GlassFish Jersey JAX-RS, j'ai résolu ce problème par la méthode commune qui décrit tous les paramètres communs. Au moins trois des paramètres doivent être égaux: nom (= "nom"), chemin (= "/") et domaine (= 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;
}

Et utilisez-le de la manière courante pour définir un cookie:

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

et pour supprimer le cookie:

NewCookie domainNewCookie = RsCookieHelper.createDomainCookie("", 0);
Response res = Response.status(Response.Status.OK).cookie(domainNewCookie).build();
RoutesMaps.com
la source
pour moi, lorsque je mets maxAge à 0, il génère un cookie avec Max-Age = 0 que Chrome semble ignorer. Dans la section 4.1.1 de la RFC 6265, il spécifie la syntaxe de Max-Age comme "non-zéro-chiffre". Cela pourrait être la raison. Bien que, comme mentionné par @ JoshC13, la section 5.2.2 parle d'interprétation des valeurs inférieures ou égales à zéro. Donc, ça se contredit un peu là-bas ...
Matthijs Wessels
Je ne connais pas les détails, mais ces valeurs par paire fonctionnent vraiment dans Chrome et d'autres navigateurs: maxAgeInMinutes * 60, expiration.
RoutesMaps.com
1
@MatthijsWessels Bonne prise! J'ai creusé un peu plus profondément, et la contradiction apparente est en fait intentionnelle, comme indiqué dans l'errata sur rfc-editor.org/errata/eid3430 . Pour "maximiser l'interopérabilité", les agents utilisateurs sont tenus d'interpréter un zéro ou un négatif Max-Agecomme la date et l'heure représentables les plus anciennes, mais il est interdit aux serveurs d'envoyer une telle Max-Agevaleur. Je suppose que les auteurs connaissaient à la fois les clients existants qui ne pouvaient pas gérer Max-Age=0et les serveurs qui les avaient envoyés au moment où ils ont écrit la spécification, et ont essayé d'atténuer le problème des deux côtés.
Mark Amery
@ Crimean.us Je ne peux plus faire de repro non plus. Peut-être que j'ai fait quelque chose de mal
Matthijs Wessels
@MatthijsWessels Le problème avec ignore Max-Age = 0 est résolu dans mon exemple en définissant la date d'expiration sur ZonedDateTime.now (). PlusMinutes (maxAgeInMinutes). Pour maxAgeInMinutes = 0, il s'agit de la date / heure actuelle. Ce code fonctionne depuis longtemps dans la vraie application Web.
RoutesMaps.com