web-dev-qa-db-fra.com

Caractères autorisés dans les cookies

celui-ci est un quickie:

Quels sont les caractères autorisés dans le nom et la valeur du cookie? Sont-ils les mêmes que l'URL ou un sous-ensemble commun?

La raison que je vous pose est que j'ai récemment rencontré un comportement étrange avec des cookies dont le nom est _-_ et je me demande simplement s'il s'agit d'un navigateur spécifique ou si mon code est défectueux.

283
Esko

celui-ci est un quickie:

Vous pensez peut-être que ce devrait être le cas, mais ce n'est vraiment pas du tout!

Quels sont les caractères autorisés dans le nom et la valeur du cookie?

Selon l'ancien Netscape cookie_spec , toute la chaîne NAME=VALUE est:

une séquence de caractères excluant le point-virgule, la virgule et les espaces.

Donc, - devrait fonctionner, et cela semble être OK dans les navigateurs que j'ai ici; Où avez-vous des problèmes avec ça?

Par implication de ce qui précède:

  • = est légal à inclure, mais potentiellement ambigu. Les navigateurs séparent toujours le nom et la valeur du premier symbole = de la chaîne. En pratique, vous pouvez donc insérer un symbole = dans la valeur mais pas le nom.

Ce qui n'est pas mentionné, parce que Netscape a été terrible en rédaction de spécifications, mais semble être systématiquement pris en charge par les navigateurs:

  • soit le nom ou la valeur peut être des chaînes vides

  • s'il n'y a pas du tout de symbole = dans la chaîne, les navigateurs le considèrent comme un cookie portant le nom de chaîne vide, c'est-à-dire que Set-Cookie: foo est identique à Set-Cookie: =foo.

  • lorsque les navigateurs émettent un cookie avec un nom vide, ils omettent le signe égal. Donc, Set-Cookie: =bar engendre Cookie: bar.

  • les virgules et les espaces dans les noms et les valeurs semblent effectivement fonctionner, bien que les espaces autour du signe égal soient coupés

  • les caractères de contrôle (\x00 à \x1F plus \x7F) ne sont pas autorisés

Ce qui n'est pas mentionné et les navigateurs sont totalement incohérents, ce sont des caractères non-ASCII (Unicode):

  • dans Opera et Google Chrome, ils sont codés dans les en-têtes Cookie avec UTF-8;
  • dans IE, la page de code par défaut de la machine est utilisée (spécifique à l'environnement local et jamais à UTF-8);
  • Firefox (et les autres navigateurs basés sur Mozilla) utilise seul l'octet de poids faible de chaque point de code UTF-16 (ISO-8859-1 est donc correct, mais tout ce qui reste est modifié);
  • Safari refuse simplement d'envoyer un cookie contenant des caractères non-ASCII.

en pratique, vous ne pouvez donc pas utiliser de caractères non-ASCII dans les cookies. Si vous souhaitez utiliser Unicode, des codes de contrôle ou d'autres séquences d'octets arbitraires, cookie_spec vous demande d'utiliser un schéma de codage ad-hoc de votre choix et de suggérer un codage d'URL (tel que produit par la variable encodeURIComponent de JavaScript) comme choix raisonnable. .

En termes de standards , il y a eu quelques tentatives de codification du comportement des cookies, mais aucune à ce jour ne reflète réellement le monde réel.

  • RFC 2109 était une tentative de codification et de correction du cookie_spec d'origine de Netscape. Dans cette norme, de nombreux autres caractères spéciaux sont interdits, car ils utilisent RFC 2616 jetons (un - est toujours autorisée ici), et seule la valeur peut être spécifiée dans une chaîne entre guillemets avec d’autres caractères. Aucun navigateur n'a jamais mis en œuvre les limitations, le traitement spécial des chaînes citées et des échappements, ni les nouvelles fonctionnalités de cette spécification.

  • RFC 2965 a été une autre tentative, en rangeant 2109 et en ajoutant davantage de fonctionnalités dans le cadre d’un système de "cookies de version 2". Personne n’a jamais mis cela en œuvre non plus. Cette spécification a les mêmes limitations de token-and-quoted-string que la version précédente et est tout aussi lourde de sens.

  • RFC 6265 est une tentative de l'ère HTML5 pour nettoyer le gâchis historique. Cela ne correspond toujours pas exactement à la réalité, mais c'est beaucoup mieux que les tentatives précédentes - c'est au moins un sous-ensemble correct de ce que les navigateurs supportent, n'introduisant aucune syntaxe supposée fonctionner mais ne fonctionnant pas (comme la chaîne entre guillemets précédente) .

Dans 6265, le nom du cookie est toujours spécifié en tant que RFC 2616 token, ce qui signifie que vous pouvez choisir parmi les alphanums plus:

!#$%&'*+-.^_`|~

Dans la valeur du cookie, il interdit formellement les caractères de contrôle (filtrés par les navigateurs) et les caractères non-ASCII (mis en œuvre de manière incohérente). Il conserve l'interdiction de cookie_spec concernant les espaces, les virgules et les points-virgules, ainsi que la compatibilité avec les idiots pauvres ayant implémenté les RFC antérieures. la valeur, pas un schéma de codage). Cela vous laisse donc avec les alphanums plus:

!#$%&'()*+-./:<=>?@[]^_`{|}~

Dans le monde réel, nous utilisons toujours le cookie_spec original de Netscape. Le code qui consomme des cookies doit donc être prêt à rencontrer pratiquement tout, mais pour le code qui produit des cookies, il est conseillé de s'en tenir au sous-ensemble de la RFC 6265.

367
bobince

Dans ASP.Net, vous pouvez utiliser System.Web.HttpUtility pour coder en toute sécurité la valeur du cookie avant de l'écrire dans le cookie et de le reconvertir sous sa forme d'origine lors de sa lecture.

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

Cela empêchera les esperluettes et signes égaux de fractionner une valeur en un ensemble de paires nom/valeur lorsqu’elle est écrite dans un cookie.

28
stephen

Je pense que c'est généralement spécifique au navigateur. Pour être sûr, base64 encode un objet JSON et stocke tout ce qu'il contient. De cette façon, il vous suffit de le décoder et d'analyser le JSON. Tous les caractères utilisés en base64 devraient fonctionner correctement avec la plupart des navigateurs, sinon tous.

17
Jamie Rumbelow

La voici, en aussi peu de mots que possible. Concentrez-vous sur les personnages qui n'ont pas besoin d'échapper

Pour les cookies:

abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!#$%&'()*+-./:<>?@[]^_`{|}~

Pour les urls

abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789.-_~!$&'()*+,;=:@

Pour les cookies et les urls (intersection)

abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!$&'()*+-.:@_~

C'est comme ça que vous répondez.

Notez que pour les cookies, le = a été supprimé car il est généralement utilisé pour définir la valeur du cookie.

Pour les urls, ce the = a été conservé. L'intersection est évidemment sans.

var chars = "abdefghijklmnqrstuvxyz"; chars += chars.toUpperCase() + "0123456789" + "!$&'()*+-.:@_~";

Il s'avère que des échappements sont toujours d'actualité et inattendus, en particulier dans un environnement de cookie Java où le cookie est entouré de guillemets doubles s'il rencontre les derniers caractères.

Donc, pour être sûr, utilisez simplement A-Za-z1-9. C'est ce que je vais faire.

10
momomo

Plus récent rfc6265 publié en avril 2011:

cookie-header = "Cookie:" OWS cookie-string OWS
cookie-string = cookie-pair *( ";" SP cookie-pair )
cookie-pair  = cookie-name "=" cookie-value
cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )

cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
                   ; US-ASCII characters excluding CTLs,
                   ; whitespace DQUOTE, comma, semicolon,
                   ; and backslash

Si vous regardez @ bobince répondez, vous verrez cette restriction plus récente plus stricte.

8
gavenkoa

vous ne pouvez pas mettre ";" dans le champ de valeur d'un cookie, le nom qui sera défini est la chaîne jusqu'à ce que le ";" dans la plupart des navigateurs ...

6
hagay onn

Il y a 2 versions de spécifications de cookies
1. Cookies de la version 0, également appelés cookies de Netscape,
2. Version 1 aussi appelé RFC 2965 cookies
Dans la version 0 Le nom et la valeur des cookies sont des séquences de caractères, à l'exclusion du point-virgule, de la virgule, du signe égal et des espaces, s'ils ne sont pas utilisés avec des guillemets
la version 1 est beaucoup plus compliquée, vous pouvez le vérifier ici
Dans cette version, les spécifications de la valeur de nom sont presque les mêmes, sauf que le nom ne peut pas commencer par le signe $

1
Tinku

Il y a un autre problème intéressant avec IE et Edge. Les cookies portant des noms de plus d'une période semblent être supprimés en mode silencieux. Donc ça marche:

cookie_name_a = valeur

alors que cela va tomber

cookie.name.a = valeur

1
Arvoreen

c'est simple:

Un <nom de cookie> peut être n’importe quel caractère US-ASCII, à l’exception des caractères de contrôle (CTL), des espaces ou des tabulations. Il ne doit pas non plus contenir de caractère de séparation tel que: () <> @,; :\"/ []? = {}.

Une <cookie-value> peut éventuellement être définie entre guillemets et tous les caractères US-ASCII, à l'exception des CTL, des espaces, des guillemets, des virgules, des points-virgules et des barres obliques inverses sont autorisés. Encodage: de nombreuses implémentations effectuent l'encodage URL sur les valeurs de cookie, mais cela n'est pas requis par la spécification RFC. Cela aide cependant à satisfaire aux exigences concernant les caractères autorisés.

Lien: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Directives

0
webolizzer

Une autre considération. J'ai récemment implémenté un schéma dans lequel certaines données sensibles envoyées à un script PHP devaient être converties et renvoyées sous forme de cookie crypté, qui utilisait toutes les valeurs base64 que je pensais garanties "en sécurité". J'ai donc crypté consciencieusement le Les éléments de données utilisant RC4, ont exécuté la sortie via base64_encode et ont heureusement renvoyé le cookie sur le site. Les tests semblaient bien se dérouler jusqu’à ce qu’une chaîne encodée en base64 contienne le symbole "+". les diagnostics du navigateur pour lesquels je pouvais également vérifier que les cookies étaient écrits étaient inchangés. Puis, lorsqu'une page suivante appelée mon PHP et obtenait le cookie via le tableau $ _COOKIE, j'étais balbutié pour constater que la chaîne manquait maintenant du caractère "+ "signe. Chaque occurrence de ce caractère a été remplacée par un espace ASCII.

Vu le nombre de plaintes similaires non résolues que j'ai lues et décrivant ce scénario depuis lors, citant souvent de nombreuses références à l'utilisation de base64 pour stocker "en toute sécurité" des données arbitraires dans des cookies, j'ai pensé signaler le problème et proposer ma solution certes totalement discrète.

Une fois que vous avez effectué le chiffrement souhaité sur une donnée, puis que vous avez utilisé base64_encode pour le rendre "sûr pour les cookies", exécutez la chaîne de sortie via cette ...

// from browser to PHP. substitute troublesome chars with 
// other cookie safe chars, or vis-versa.  

function fix64($inp) {
    $out =$inp;
    for($i = 0; $i < strlen($inp); $i++) {
        $c = $inp[$i];
        switch ($c) {
            case '+':  $c = '*'; break; // definitly won't transfer!
            case '*':  $c = '+'; break;

            case '=':  $c = ':'; break; // = symbol seems like a bad idea
            case ':':  $c = '='; break;

            default: continue;
            }
        $out[$i] = $c;
        }
    return $out;
    }

Ici, je remplace simplement "+" (et j'ai décidé "=" aussi) par d'autres caractères "cookie safe", avant de renvoyer la valeur codée à la page, pour l'utiliser comme cookie. Notez que la longueur de la chaîne en cours de traitement ne change pas. Lorsque la même (ou une autre page du site) relance mon script PHP, je pourrai récupérer ce cookie sans qu'il ne manque de caractères. Je dois juste me rappeler de restituer le cookie via le même appel fix64 () que j'ai créé et à partir de là, je peux le décoder avec la base64_decode () habituelle, suivie de tout autre décryptage de votre schéma.

Il se peut que je puisse effectuer un paramétrage dans PHP qui permette de retransférer les chaînes base64 utilisées dans les cookies sur PHP sans les endommager. En attendant, cela fonctionne. Le "+" peut être une valeur de cookie "légale", mais si vous souhaitez pouvoir renvoyer une telle chaîne à PHP (dans mon cas via le tableau $ _COOKIE), je suis suggérant un nouveau traitement pour supprimer les caractères incriminés et les restaurer après la récupération. Il y a beaucoup d'autres personnages "sûrs des cookies" à choisir.

0
Randy