Quels sont les caractères autorisés dans les cookies?

301

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

La raison pour laquelle je demande est que j'ai récemment rencontré un comportement étrange avec des cookies qui ont -leur nom et je me demande simplement si c'est quelque chose de spécifique au navigateur ou si mon code est défectueux.

Esko
la source

Réponses:

391

celui-ci est un quickie:

Vous pourriez penser que cela devrait l'être, 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 cookie_spec de Netscape, la NAME=VALUEchaîne entière est:

une séquence de caractères excluant les points-virgules, les virgules et les espaces blancs.

-Cela devrait donc 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 divisent toujours le nom et la valeur sur le premier =symbole de la chaîne, donc en pratique vous pouvez mettre un =symbole dans la VALEUR mais pas le NOM.

Ce qui n'est pas mentionné, car Netscape était horrible lors de l'écriture de spécifications, mais semble toujours pris en charge par les navigateurs:

  • le NOM ou la VALEUR peuvent être des chaînes vides

  • s'il n'y a aucun =symbole dans la chaîne, les navigateurs le traitent comme le cookie avec le nom de chaîne vide, c'est Set-Cookie: foo-à- dire le même que Set-Cookie: =foo.

  • lorsque les navigateurs génèrent un cookie avec un nom vide, ils omettent le signe égal. Alors Set-Cookie: =barengendre Cookie: bar.

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

  • les caractères de contrôle ( \x00en \x1Fplus \x7F) ne sont pas autorisés

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

  • dans Opera et Google Chrome, ils sont encodés en en-têtes de cookie avec UTF-8;
  • dans IE, la page de codes par défaut de la machine est utilisée (spécifique aux paramètres régionaux et jamais UTF-8);
  • Firefox (et d'autres navigateurs basés sur Mozilla) utilisent seul l'octet de poids faible de chaque point de code UTF-16 (donc ISO-8859-1 est OK mais tout le reste est mutilé);
  • Safari refuse simplement d'envoyer tout cookie contenant des caractères non ASCII.

dans la pratique, vous ne pouvez donc pas utiliser du tout 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, le cookie_spec vous demande d'utiliser un schéma de codage ad hoc de votre choix et de suggérer un codage URL (tel que produit par JavaScript encodeURIComponent) comme un choix raisonnable.

En termes de normes réelles , il y a eu quelques tentatives de codification du comportement des cookies, mais aucune ne reflète jusqu'à présent le monde réel.

  • La RFC 2109 était une tentative de codification et de correction du cookie_spec Netscape d'origine. Dans cette norme, de nombreux autres caractères spéciaux sont interdits, car il utilise des jetons RFC 2616 (a y -est toujours autorisé), 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 implémenté les limitations, la gestion spéciale des chaînes entre guillemets et des échappements, ou les nouvelles fonctionnalités de cette spécification.

  • Le RFC 2965 a été une autre tentative, rangeant 2109 et ajoutant plus de fonctionnalités dans le cadre d'un schéma de «cookies de version 2». Personne n'a jamais mis en œuvre cela non plus. Cette spécification a les mêmes limitations de chaîne de jetons et de chaînes que la version précédente et c'est tout autant une charge de non-sens.

  • La RFC 6265 est une tentative de l'ère HTML5 pour éliminer 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 approprié de ce que les navigateurs prennent en charge, n'introduisant aucune syntaxe censée fonctionner mais qui ne fonctionne pas (comme la chaîne citée précédente) .

Dans 6265, le nom du cookie est toujours spécifié comme 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 sur l'espace, la virgule et le point-virgule, ainsi que pour la compatibilité avec tous les idiots pauvres qui ont effectivement mis en œuvre les RFC antérieurs, il a également interdit la barre oblique inverse et les guillemets, autres que les guillemets enveloppant la valeur entière (mais dans ce cas, les guillemets sont toujours considérés comme faisant partie de la valeur, pas un schéma de codage). Cela vous laisse donc avec les alphanums plus:

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

Dans le monde réel, nous utilisons toujours l'original et le pire Netscape cookie_spec, donc le code qui consomme des cookies doit être prêt à rencontrer à peu près n'importe quoi, mais pour le code qui produit des cookies, il est conseillé de s'en tenir au sous-ensemble dans la RFC 6265.

bobince
la source
@bobince Voulez-vous dire que la RFC indique que les valeurs des cookies peuvent avoir le ;caractère tant qu'il est entouré de guillemets doubles? En tant que tel:Set-Cookie: Name=Va";"lue; Max-Age=3600
Pacerier
@Pacerier: la valeur entière devrait être une chaîne entre guillemets, donc elle devrait l'être Name="Va;lue"; max-age.... Cela ne fonctionne pas dans les navigateurs et ce n'est pas autorisé dans la RFC 6265, qui est proposée pour remplacer 2965 et tente de refléter un peu mieux la réalité.
bobince
@bobince - Je sais que c'est ancien, mais est-ce que je lis correctement votre réponse pour signifier que les espaces ne sont pas techniquement autorisés dans les valeurs des cookies? "à l'exclusion des points-virgules, des virgules et des espaces blancs " [c'est moi qui souligne]
Adam Rackis
1
@Adam: Oui, si vous respectez la spécification Netscape ou la RFC 6265, les espaces blancs ne sont pas autorisés dans une valeur de cookie brute (non DQUOTEd). Il fonctionne néanmoins dans les navigateurs que j'ai essayés, mais je ne m'y fierais pas.
bobince
2
RFC 6265 définit comme un jeton 1*<any CHAR except CTLs or separators>et les séparateurs sont (, ), <, >, @, ,, ;, :, \, ", /, [, ], ?, =, {, }, SPet HT, donc les noms de cookies doivent être des caractères alphanumériques , plus!#$%&'*+-.?^_`|~
Gan Quan
28

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

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

Cela arrêtera les esperluettes et équivaudra à des signes divisant une valeur en un groupe de paires nom / valeur lors de son écriture dans un cookie.

Stephen
la source
1
Juste une note, asp.net utilise en interne le codage hexadécimal au lieu de UrlEncode lors du stockage du cookie d'authentification. referencesource.microsoft.com # System.Web / Security /… donc il peut y avoir des cas où le codage url ne le coupera pas?
Peter
17

Je pense que c'est généralement spécifique au navigateur. Pour être sûr, base64 code 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 dans base64 devraient fonctionner correctement avec la plupart, sinon tous les navigateurs.

Jamie Rumbelow
la source
Cette réponse semble être la plus cohérente parmi les navigateurs. Je m'en suis rendu compte après avoir travaillé de nombreuses heures à essayer d'obtenir une solution rapide: je n'en ai pas eu non plus. Faites comme recommandé exactement ci-dessus pour vous éviter les tracas.
sourire
Je n'ai pas essayé cela, mais j'ai lu d'autres articles à ce sujet disant que l'encodage base64 ne fonctionne qu'avec des caractères ascii.
user984003
11

La voici, en un minimum de mots . Concentrez-vous sur les personnages qui n'ont pas besoin de s'échapper:

Pour les cookies:

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

Pour les URL

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

Pour les cookies et les URL (intersection)

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

Voilà comment 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 URL, le = a été conservé. L'intersection est évidemment sans.

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

Il s'avère que l'échappement se produit toujours et se produit de manière inattendue, 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. Voilà ce que je vais faire.

mmm
la source
Safari Cookies était mon seul problème de navigateur - tous les autres navigateurs fonctionnaient bien. J'ai dû UrlEncode et UrlDecode mon cookie pour gérer les signes et les espaces égaux =. Comme un Base64Encode dans le cookie. (Safari seulement requis cela - d'autres navigateurs ont bien fonctionné avec et sans le cookie codé.)
Sql Surfer
Il est préférable de répertorier les sources menant à votre réponse!
Loc
1
@Loc Plus de 3 heures d'essai et d'inspection.
mmm
10

Rfc6265 plus récent 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épondre, vous voyez que les nouvelles restrictions sont plus strictes.

gavenkoa
la source
6

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

hagay onn
la source
1

Il existe 2 versions des spécifications des cookies
1. Cookies de la version 0 aka cookies Netscape,
2. Cookies de la version 1 aka RFC 2965
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 de l'espace. , sinon utilisé avec des guillemets doubles
version 1 est beaucoup plus compliqué que vous pouvez vérifier ici
Dans cette specs version pour une partie de la valeur du nom est presque identique sauf le nom ne peut pas commencer par $ signe

Tinku
la source
Où est-il dit que les valeurs doivent exclure le signe égal dans la version 0?
Gili
1

Il y a un autre problème intéressant avec IE et Edge. Les cookies dont le nom comporte plus d'une période semblent être supprimés en silence. Cela fonctionne donc:

cookie_name_a = valuea

alors que cela sera abandonné

cookie.name.a = valuea

Arvoreen
la source
Ce serait formidable si vous ajoutez la version exacte du navigateur pour que nous puissions répliquer, car le comportement du navigateur n'est pas cohérent avec les cookies.
Gerald
0

c'est simple:

Un <cookie-name> 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 comme le suivant: () <> @,; : \ "/ []? = {}.

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

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

webolizzer
la source
0

Encore une considération. J'ai récemment implémenté un schéma dans lequel certaines données sensibles publiées dans un script PHP devaient être converties et renvoyées sous forme de cookie crypté, qui utilisait toutes les valeurs de base64 que je pensais être garanties "en sécurité". J'ai donc crypté consciencieusement les éléments de données à l'aide de RC4, j'ai exécuté la sortie via base64_encode, et a heureusement renvoyé le cookie sur le site. Les tests ont semblé bien se passer jusqu'à ce qu'une chaîne encodée en base64 contienne un symbole "+". La chaîne a été écrite sans problème dans le cookie de la page. En utilisant les diagnostics du navigateur, j'ai également pu vérifier que les cookies ont été écrits inchangés. Puis, quand une page suivante a appelé mon PHP et a obtenu le cookie via le tableau $ _COOKIE, j'ai été balbutié pour trouver que la chaîne manquait maintenant le signe "+". Chaque occurrence de ce caractère a été remplacée par un Espace ASCII.

Compte tenu du nombre de plaintes non résolues similaires que j'ai lues depuis lors, décrivant ce scénario, 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 délirante.

Une fois que vous avez effectué le cryptage que vous souhaitez effectuer sur une donnée, puis utilisé base64_encode pour le rendre "cookie-safe", exécutez la chaîne de sortie à travers ceci ...

// 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é "=" également) par d'autres caractères "sans danger pour les cookies", avant de retourner la valeur codée à la page, pour une utilisation en tant que 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) exécute à nouveau mon script PHP, je pourrai récupérer ce cookie sans manquer de caractères. Je dois juste me rappeler de transmettre le cookie via le même appel fix64 () que j'ai créé, et à partir de là, je peux le décoder avec l'habituel base64_decode (), suivi de tout autre déchiffrement de votre schéma.

Il pourrait y avoir un paramètre que je pourrais faire en PHP qui permette aux chaînes base64 utilisées dans les cookies d'être retransférées vers PHP sans corruption. En attendant, cela fonctionne. Le "+" peut être une valeur de cookie "légale", mais si vous souhaitez pouvoir retransmettre une telle chaîne à PHP (dans mon cas via le tableau $ _COOKIE), je suggère de retraiter pour supprimer les personnages offensants et les restaurer après la récupération. Il existe de nombreux autres personnages "sans danger pour les cookies" parmi lesquels choisir.

Excité
la source
0

Si vous utilisez les variables plus tard, vous constaterez que des éléments comme ceux- pathci laisseront passer les caractères accentués, mais ne correspondront pas réellement au chemin du navigateur. Pour cela, vous devez les saisir URIEncode. Donc, c'est comme ça:

  const encodedPath = encodeURI(myPath);
  document.cookie = `use_pwa=true; domain=${location.host}; path=${encodedPath};`

Ainsi, les caractères "autorisés" pourraient être plus que ce qui est dans la spécification. Mais vous devez rester dans la spécification et utiliser des chaînes codées par URI pour être sûr.

odinho - Velmont
la source
-1

Il y a des années, MSIE 5 ou 5.5 (et probablement les deux) avait un sérieux problème avec un "-" dans le bloc HTML si vous pouvez le croire. Bien qu'il ne soit pas directement lié, depuis que nous avons stocké un hachage MD5 (contenant uniquement des lettres et des chiffres) dans le cookie pour rechercher tout le reste dans la base de données côté serveur.

FYA
la source
-2

J'ai fini par utiliser

cookie_value = encodeURIComponent(my_string);

et

my_string = decodeURIComponent(cookie_value);

Cela semble fonctionner pour toutes sortes de personnages. J'ai eu des problèmes étranges autrement, même avec des caractères qui n'étaient pas des points-virgules ou des virgules.

user984003
la source