¿Qué son los caracteres permitidos en las cookies?

301

¿Cuáles son los caracteres permitidos tanto en el nombre como en el valor de la cookie? ¿Son iguales a URL o algún subconjunto común?

La razón por la que pregunto es que recientemente he tenido un comportamiento extraño con las cookies que tienen -en su nombre y me pregunto si es algo específico del navegador o si mi código es defectuoso.

Esko
fuente

Respuestas:

391

este es un rapidito:

Podrías pensar que debería ser, ¡pero realmente no lo es en absoluto!

¿Cuáles son los caracteres permitidos tanto en el nombre como en el valor de la cookie?

Según el antiguo Netscape cookie_spec, la NAME=VALUEcadena completa es:

Una secuencia de caracteres excluyendo punto y coma, coma y espacio en blanco.

Entonces -debería funcionar, y parece estar bien en los navegadores que tengo aquí; ¿Dónde tienes problemas con eso?

Por implicación de lo anterior:

  • =es legal incluir, pero potencialmente ambiguo. Los navegadores siempre dividen el nombre y el valor en el primer =símbolo de la cadena, por lo que en la práctica puede poner un =símbolo en el VALOR pero no en el NOMBRE.

Lo que no se menciona, porque Netscape era terrible para escribir especificaciones, pero parece ser compatible con los navegadores:

  • el NOMBRE o el VALOR pueden ser cadenas vacías

  • Si no hay ningún =símbolo en la cadena, los navegadores lo tratan como la cookie con el nombre de la cadena vacía, Set-Cookie: fooes decir, es el mismo que Set-Cookie: =foo.

  • cuando los navegadores generan una cookie con un nombre vacío, omiten el signo igual. Así Set-Cookie: =barengendra Cookie: bar.

  • las comas y espacios en nombres y valores realmente parecen funcionar, aunque los espacios alrededor del signo igual están recortados

  • los caracteres de control ( \x00a \x1Fmás \x7F) no están permitidos

Lo que no se menciona y los navegadores son totalmente inconsistentes, son los caracteres no ASCII (Unicode):

  • en Opera y Google Chrome, están codificados en encabezados de cookies con UTF-8;
  • en IE, se usa la página de códigos predeterminada de la máquina (específica de la localidad y nunca UTF-8);
  • Firefox (y otros navegadores basados ​​en Mozilla) usan el byte bajo de cada punto de código UTF-16 por sí solo (por lo que ISO-8859-1 está bien, pero cualquier otra cosa está destrozada);
  • Safari simplemente se niega a enviar cualquier cookie que contenga caracteres no ASCII.

por lo tanto, en la práctica no puede usar caracteres que no sean ASCII en las cookies. Si desea utilizar Unicode, códigos de control u otras secuencias de bytes arbitrarias, cookie_spec exige que utilice un esquema de codificación ad-hoc de su elección y sugiera la codificación de URL (como la producida por JavaScript encodeURIComponent) como una opción razonable.

En términos de estándares reales , ha habido algunos intentos de codificar el comportamiento de las cookies, pero ninguno hasta el momento realmente refleja el mundo real.

  • RFC 2109 fue un intento de codificar y corregir la cookie_spec original de Netscape. En esta Norma muchos más caracteres especiales no están permitidas, ya que utiliza el RFC 2616 fichas (una -está siendo permitidas allí), y sólo el valor puede ser especificado en una cita de cadena con otros personajes. Ningún navegador implementó las limitaciones, el manejo especial de cadenas y escapes entre comillas, o las nuevas características de esta especificación.

  • RFC 2965 fue otra oportunidad, ordenó 2109 y agregó más funciones bajo un esquema de 'cookies de la versión 2'. Nadie implementó nada de eso tampoco. Esta especificación tiene las mismas limitaciones de cadena de tokens y comillas que la versión anterior y es una carga de tonterías.

  • RFC 6265 es un intento de la era HTML5 para aclarar el desorden histórico. Todavía no coincide con la realidad exactamente, pero es mucho mejor que los intentos anteriores: es al menos un subconjunto adecuado de lo que admiten los navegadores, no presenta ninguna sintaxis que se supone que funciona pero no funciona (como la cadena citada anterior) .

En 6265, el nombre de la cookie todavía se especifica como RFC 2616 token, lo que significa que puede elegir entre los alfanum más:

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

En el valor de la cookie, prohíbe formalmente los caracteres de control (filtrados por los navegadores) y los caracteres no ASCII (implementados de manera inconsistente). Conserva la prohibición de cookie_spec sobre el espacio, la coma y el punto y coma, además de la compatibilidad con cualquier idiota pobre que realmente implementó los RFC anteriores, también prohibió la barra invertida y las comillas, aparte de las comillas que envuelven todo el valor (pero en ese caso las comillas todavía se consideran parte de el valor, no un esquema de codificación). Entonces eso te deja con los alfanum más:

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

En el mundo real, todavía usamos la cookie_spec original y peor de Netscape, por lo que el código que consume cookies debe estar preparado para encontrar casi cualquier cosa, pero para el código que produce cookies es recomendable quedarse con el subconjunto en RFC 6265.

bobince
fuente
@bobince ¿Quiere decir que el RFC establece que los valores de cookie pueden tener el ;carácter siempre que esté entre comillas dobles? Como tal:Set-Cookie: Name=Va";"lue; Max-Age=3600
Pacerier
@Pacerier: todo el valor debería ser una cadena entre comillas, por lo que debería serlo Name="Va;lue"; max-age.... No funciona en navegadores y no está permitido en RFC 6265, que se propone reemplazar 2965 e intenta reflejar un poco mejor la realidad.
bobince
@bobince: sé que esto es antiguo, pero ¿estoy leyendo su respuesta correctamente para indicar que los espacios no están técnicamente permitidos en los valores de cookies? "excluyendo punto y coma, coma y espacio en blanco " [énfasis mío]
Adam Rackis
1
@ Adam: Sí, si utiliza la especificación Netscape o RFC 6265, no se permite el espacio en blanco en un valor de cookie sin formato (sin DOTOTEd). No obstante, funciona en los navegadores que he probado, pero no confiaría en ello.
bobince
2
RFC 6265 define como simbólico 1*<any CHAR except CTLs or separators>y separadores son (, ), <, >, @, ,, ;, :, \, ", /, [, ], ?, =, {, }, SPy HT, por lo que los nombres de cookies deberían ser más alphanums!#$%&'*+-.?^_`|~
Gan Quan
28

En ASP.Net puede usar System.Web.HttpUtilitypara codificar de forma segura el valor de la cookie antes de escribir en la cookie y convertirla nuevamente a su forma original al leerla.

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

Esto detendrá los signos de unión y los signos iguales que dividen un valor en un grupo de pares de nombre / valor a medida que se escribe en una cookie.

Stephen
fuente
1
Solo una nota, internamente asp.net usa codificación hexadecimal en lugar de UrlEncode cuando almacena la cookie de autenticación. referencesource.microsoft.com # System.Web / Security / ... entonces, ¿podría haber algunos casos en los que la codificación de URL no sea suficiente?
Peter
17

Creo que generalmente es específico del navegador. Para estar seguro, base64 codifica un objeto JSON y almacena todo en él. De esa manera solo tienes que decodificarlo y analizar el JSON. Todos los caracteres utilizados en base64 deberían funcionar bien con la mayoría, si no con todos los navegadores.

Jamie Rumbelow
fuente
Esta respuesta parece ser consistente en todos los navegadores. Me di cuenta de esto después de trabajar muchas horas tratando de obtener una solución rápida: tampoco obtuve una. Simplemente haga lo recomendado exactamente arriba para ahorrarse las molestias.
sonríe el
No probé esto, pero leí otras publicaciones sobre esto diciendo que la codificación base64 solo funciona con caracteres ascii.
user984003
11

Aquí está, en la menor cantidad de palabras posible . Concéntrese en los personajes que no necesitan escapar:

Para las cookies:

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

Para urls

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

Para cookies y urls (intersección)

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

Así es como respondes.

Tenga en cuenta que para las cookies, el = se ha eliminado porque generalmente se usa para establecer el valor de la cookie.

Para urls esto se mantuvo el =. La intersección es obviamente sin.

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

Resulta que el escape sigue ocurriendo y ocurre inesperadamente, especialmente en un entorno de cookies Java donde la cookie se envuelve con comillas dobles si encuentra los últimos caracteres.

Entonces, para estar seguro, solo use A-Za-z1-9. Eso es lo que voy a hacer.

mmm
fuente
Safari Cookies fue mi único problema con el navegador: todos los demás navegadores funcionaron bien. Tuve que UrlEncode y UrlDecode mi cookie para lidiar con igualdad = signos y espacios. Como un Base64Encode en la cookie. (Safari solo requería esto: otros navegadores funcionaban bien con y sin la cookie codificada.)
Sql Surfer
¡Es mejor si enumera qué fuentes conducen a su respuesta!
Loc
1
@Loc Más de 3 horas de prueba e inspección.
mmm
10

Más reciente rfc6265 publicado en abril de 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 observa la respuesta de @bobince , verá que las restricciones más nuevas son más estrictas.

gavenkoa
fuente
6

no puedes poner ";" en el campo de valor de una cookie, el nombre que se establecerá es la cadena hasta el ";" en la mayoría de los navegadores ...

hagay onn
fuente
1

Existen 2 versiones de las especificaciones de cookies
1. Cookies de la versión 0, también conocidas como cookies de Netscape,
2. Versión 1, también conocidas como cookies RFC 2965
En la versión 0 El nombre y el valor de las cookies son secuencias de caracteres, excluyendo el punto y coma, la coma, el signo igual y el espacio en blanco. , si no se utiliza con comillas dobles
versión 1 es mucho más complicado que puede comprobar que aquí
en esta versión especificaciones de valor de nombre de la pieza es casi igual, excepto nombre no puede comenzar con $ signo

Tinku
fuente
¿Dónde dice que los valores deben excluir el signo igual en la versión 0?
Gili
1

Hay otro problema interesante con IE y Edge. Las cookies que tienen nombres con más de 1 punto parecen descartarse en silencio. Entonces esto funciona:

cookie_name_a = valuea

mientras que esto se caerá

cookie.name.a = valuea

Arvoreen
fuente
Sería genial si agrega la versión exacta del navegador para que podamos replicar, ya que el comportamiento del navegador no es consistente con las cookies.
Gerald
0

así de simple:

Un <nombre de cookie> puede ser cualquier carácter ASCII de EE. UU., Excepto los caracteres de control (CTL), espacios o pestañas. Tampoco debe contener un carácter separador como el siguiente: () <> @,; : \ "/ []? = {}.

Opcionalmente, se puede establecer un <cookie-value> entre comillas dobles y se permiten los caracteres ASCII de EE. UU., Excepto CTL, espacios en blanco, comillas dobles, coma, punto y coma y barra diagonal inversa. Codificación: muchas implementaciones realizan codificación de URL en valores de cookies, sin embargo, no es necesario según la especificación RFC. Sin embargo, ayuda a satisfacer los requisitos sobre qué caracteres están permitidos.

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

webolizzer
fuente
0

Una consideración más. Recientemente implementé un esquema en el que algunos datos confidenciales publicados en un script PHP necesitaban convertirlo y devolverlo como una cookie encriptada, que usaba todos los valores de base64 que creía que estaban garantizados como 'seguros'. Entonces encripte debidamente los elementos de datos usando RC4, ejecuté la salida a través de base64_encode, y felizmente devolvió la cookie al sitio. Las pruebas parecían funcionar bien hasta que una cadena codificada en base64 contenía un símbolo "+". La cadena se escribió en la cookie de la página sin problemas. Utilizando el diagnóstico del navegador también pude verifiqué que las cookies se escribieron sin cambios. Luego, cuando una página posterior llamó a mi PHP y obtuvo la cookie a través de la matriz $ _COOKIE, me tartamudeé al encontrar que a la cadena le faltaba el signo "+". Cada aparición de ese carácter fue reemplazada por un Espacio ASCII.

Teniendo en cuenta cuántas quejas no resueltas similares que he leído que describen este escenario desde entonces, a menudo ubicando numerosas referencias al uso de base64 para almacenar datos arbitrarios en cookies de forma "segura", pensé en señalar el problema y ofrecer mi solución, sin duda, muy poco acertada.

Después de que haya hecho el cifrado que desea hacer en un dato y luego haya utilizado base64_encode para que sea "seguro para cookies", ejecute la cadena de salida a través de esto ...

// 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;
    }

Aquí simplemente estoy sustituyendo "+" (y decidí "=" también) con otros caracteres "seguros para cookies", antes de devolver el valor codificado a la página, para usar como cookie. Tenga en cuenta que la longitud de la cadena que se procesa no cambia. Cuando la misma (u otra página en el sitio) ejecute mi script PHP nuevamente, podré recuperar esta cookie sin caracteres faltantes. Solo tengo que recordar pasar la cookie nuevamente a través de la misma llamada fix64 () que creé, y desde allí puedo decodificarla con el habitual base64_decode (), seguido de cualquier otro descifrado en su esquema.

Puede haber alguna configuración que pueda hacer en PHP que permita que las cadenas de base64 utilizadas en las cookies se transfieran a PHP sin corrupción. Mientras tanto, esto funciona. El "+" puede ser un valor de cookie "legal", pero si desea poder transmitir dicha cadena a PHP (en mi caso a través de la matriz $ _COOKIE), le sugiero que vuelva a procesar para eliminar personajes ofensivos, y restaurarlos después de la recuperación. Hay muchos otros caracteres "seguros para cookies" para elegir.

Cachondo
fuente
0

Si usa las variables más adelante, encontrará que cosas como en pathrealidad dejarán pasar los caracteres acentuados, pero en realidad no coincidirán con la ruta del navegador. Para eso necesitas URIE codificarlos. Entonces es así:

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

Entonces, los caracteres "permitidos" pueden ser más de lo que está en la especificación. Pero debe mantenerse dentro de la especificación y usar cadenas codificadas por URI para estar seguro.

odinho - Velmont
fuente
-1

Hace años, MSIE 5 o 5.5 (y probablemente ambos) tenían un problema grave con un "-" en el bloque HTML, si puedes creerlo. Aunque no está directamente relacionado, desde que hemos almacenado un hash MD5 (que contiene letras y números solamente) en la cookie para buscar todo lo demás en la base de datos del lado del servidor.

FYA
fuente
-2

Terminé usando

cookie_value = encodeURIComponent(my_string);

y

my_string = decodeURIComponent(cookie_value);

Eso parece funcionar para todo tipo de personajes. Tenía problemas extraños de lo contrario, incluso con personajes que no eran punto y coma o comas.

usuario984003
fuente