O que são caracteres permitidos nos cookies?

301

Quais são os caracteres permitidos no nome e no valor do cookie? Eles são iguais a URL ou algum subconjunto comum?

A razão pela qual estou perguntando é que recentemente cometi algum comportamento estranho com cookies que têm -seu nome e só estou me perguntando se é algo específico do navegador ou se meu código está com defeito.

Esko
fonte

Respostas:

391

essa é uma rapidinha:

Você pode pensar que deveria ser, mas realmente não é!

Quais são os caracteres permitidos no nome e no valor do cookie?

De acordo com o antigo cookie_spec do Netscape, a NAME=VALUEstring inteira é:

uma sequência de caracteres excluindo ponto-e-vírgula, vírgula e espaço em branco.

Portanto, -deve funcionar e parece estar bem nos navegadores que tenho aqui; onde você está tendo problemas com isso?

Por implicação do acima exposto:

  • =é legal incluir, mas potencialmente ambíguo. Os navegadores sempre dividem o nome e o valor no primeiro =símbolo da string, portanto, na prática, você pode colocar um =símbolo no VALUE, mas não no NAME.

O que não foi mencionado, porque o Netscape foi péssimo ao escrever especificações, mas parece ser consistentemente suportado pelos navegadores:

  • o NAME ou o VALUE podem ser cadeias vazias

  • se não houver nenhum =símbolo na string, os navegadores o tratam como o cookie com o nome da string vazia, ou seja, Set-Cookie: fooé o mesmo que Set-Cookie: =foo.

  • quando os navegadores emitem um cookie com um nome vazio, eles omitem o sinal de igual. Então Set-Cookie: =bargera Cookie: bar.

  • vírgulas e espaços em nomes e valores realmente parecem funcionar, embora os espaços ao redor do sinal de igual sejam aparados

  • caracteres de controle ( \x00até \x1Fmais \x7F) não são permitidos

O que não é mencionado e os navegadores são totalmente inconsistentes são caracteres não ASCII (Unicode):

  • no Opera e no Google Chrome, eles são codificados nos cabeçalhos de cookies com UTF-8;
  • no IE, a página de código padrão da máquina é usada (específica do local e nunca UTF-8);
  • O Firefox (e outros navegadores baseados no Mozilla) usam o byte baixo de cada ponto de código UTF-16 por conta própria (portanto, a ISO-8859-1 é válida, mas qualquer outra coisa é mutilada);
  • O Safari simplesmente se recusa a enviar qualquer cookie que contenha caracteres não ASCII.

portanto, na prática, você não pode usar caracteres não ASCII em cookies. Se você deseja usar Unicode, códigos de controle ou outras seqüências de bytes arbitrárias, o cookie_spec exige que você use um esquema de codificação ad-hoc de sua própria escolha e sugira a codificação de URL (conforme produzida pelo JavaScript encodeURIComponent) como uma opção razoável.

Em termos de padrões reais , houve algumas tentativas de codificar o comportamento dos cookies, mas nenhuma até agora reflete o mundo real.

  • O RFC 2109 foi uma tentativa de codificar e corrigir o cookie_spec original do Netscape. Nesse padrão, muitos caracteres especiais não são permitidos, pois ele usa tokens RFC 2616 (a ainda- é permitido lá), e somente o valor pode ser especificado em uma string entre aspas com outros caracteres. Nenhum navegador implementou as limitações, o tratamento especial das seqüências de caracteres citadas e o escape, ou os novos recursos desta especificação.

  • A RFC 2965 foi outra opção, arrumando 2109 e adicionando mais recursos no esquema de 'cookies da versão 2'. Ninguém nunca implementou nada disso também. Esta especificação tem as mesmas limitações de token e string entre aspas da versão anterior e é uma carga absurda.

  • O RFC 6265 é uma tentativa da era do HTML5 para esclarecer a bagunça histórica. Ainda não corresponde exatamente à realidade, mas é muito melhor do que as tentativas anteriores - é pelo menos um subconjunto adequado do que os navegadores suportam, não introduzindo nenhuma sintaxe que supostamente funcione, mas não funciona (como a cadeia de caracteres anterior) .

Em 6265, o nome do cookie ainda é especificado como um RFC 2616 token, o que significa que você pode escolher entre os alfanumos mais:

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

No valor do cookie, proíbe formalmente os caracteres de controle (filtrados pelos navegadores) e os caracteres não ASCII (implementados de maneira inconsistente). Ele mantém a proibição do cookie_spec em espaço, vírgula e ponto-e-vírgula, além de compatibilidade com quaisquer idiotas pobres que realmente implementaram as RFCs anteriores, também proibiu barra invertida e aspas, exceto as que envolvem todo o valor (mas, nesse caso, as aspas ainda são consideradas parte de o valor, não um esquema de codificação). Então, isso deixa você com os alfanos mais:

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

No mundo real, ainda estamos usando o cookie_spec Netscape original e o pior, portanto, o código que consome cookies deve estar preparado para encontrar praticamente qualquer coisa, mas para o código que produz cookies, é aconselhável manter o subconjunto no RFC 6265.

bobince
fonte
@bobince Você quer dizer que a RFC declara que os valores dos cookies podem ter o ;caractere contanto que esteja entre aspas duplas? Como tal:Set-Cookie: Name=Va";"lue; Max-Age=3600
Pacerier
@ Pacerier: todo o valor teria que ser uma string entre aspas, por isso teria que ser Name="Va;lue"; max-age.... Ele não funciona em navegadores e não é permitido na RFC 6265, que propõe substituir 2965 e tenta refletir um pouco melhor a realidade.
bobince
@obince - Eu sei que isso é antigo, mas estou lendo sua resposta corretamente para significar que espaços tecnicamente não são permitidos em valores de cookies? "excluindo-e-vírgula, vírgula e espaço em branco " [grifo meu]
Adam Rackis
1
@ Adam: Sim, se você estiver seguindo as especificações da Netscape ou da RFC 6265, não será permitido espaço em branco em um valor de cookie bruto (não-DQUOTEd). No entanto, ele funciona nos navegadores que eu tentei, mas não confiaria nele.
22913
2
RFC 6265 define token como 1*<any CHAR except CTLs or separators>e separadores são (, ), <, >, @, ,, ;, :, \, ", /, [, ], ?, =, {, }, SPe HT, portanto, nomes de cookies deve ser alfanuméricos mais!#$%&'*+-.?^_`|~
Gan Quan
28

No ASP.Net, você pode System.Web.HttpUtilitycodificar com segurança o valor do cookie antes de gravá-lo e convertê-lo novamente em sua forma original ao lê-lo.

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

Isso interromperá oe comercial e sinais de igual, dividindo um valor em um monte de pares nome / valor conforme ele é gravado em um cookie.

Stephen
fonte
1
Apenas uma observação: internamente, o asp.net usa codificação hex em vez do UrlEncode ao armazenar o cookie de autenticação. referencesource.microsoft.com # System.Web / Security /… então, pode haver alguns casos em que a codificação de URL não será cortada?
Pedro #
17

Eu acho que geralmente é específico do navegador. Para garantir a segurança, a base64 codifica um objeto JSON e armazena tudo nele. Dessa forma, você só precisa decodificá-lo e analisar o JSON. Todos os caracteres usados ​​no base64 devem funcionar bem com a maioria, se não com todos os navegadores.

Jamie Rumbelow
fonte
Essa resposta parece ser consistente entre os navegadores. Percebi isso depois de trabalhar muitas horas tentando obter uma solução rápida: também não recebi uma. Basta fazer o recomendado exatamente acima para evitar os aborrecimentos.
sorrir
Não tentei isso, mas li outros posts sobre isso dizendo que a codificação base64 funciona apenas com caracteres ascii.
User984003
11

Aqui está, no menor número de palavras possível . Concentre-se nos personagens que não precisam ser escapados:

Para cookies:

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

Para URLs

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

Para cookies e URLs (interseção)

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

É assim que você responde.

Observe que, para cookies, o = foi removido porque geralmente é usado para definir o valor do cookie.

Para urls, o = foi mantido. A interseção é obviamente sem.

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

Acontece que o escape ainda está ocorrendo e acontece inesperadamente, especialmente em um ambiente de cookie Java em que o cookie é colocado entre aspas duplas se encontrar os últimos caracteres.

Para ser seguro, basta usar A-Za-z1-9. É o que eu vou fazer.

mmm
fonte
O Safari Cookies era meu único problema no navegador - todos os outros navegadores funcionavam bem. Eu tive que UrlEncode e UrlDecode meu cookie para lidar com sinais e espaços iguais. Como um Base64Encode no Cookie. (Safari Só exigido this- outros navegadores funcionou bem com e sem o cookie codificado.)
Sql Surfer
É melhor se você listar quais fontes levam à sua resposta!
Loc
1
@Loc Mais de 3 horas de teste e inspeção.
mmm
10

Mais recente rfc6265 publicado em 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

Se você procurar a resposta @bobince, verá que as restrições mais recentes são mais rigorosas.

gavenkoa
fonte
6

você não pode colocar ";" no campo de valor de um cookie, o nome que será definido é a sequência até o ";" na maioria dos navegadores ...

hagay onn
fonte
1

Existem 2 versões das especificações de cookies
1. Versão 0 cookies aka cookies Netscape,
2. Versão 1 aka RFC 2965 cookies
Na versão 0 A parte de nome e valor de cookies são sequências de caracteres, excluindo ponto e vírgula, vírgula, sinal de igual e espaço em branco , se não for usado com aspas duplas, a
versão 1 é muito mais complicada, verifique aqui.
Nesta versão, as especificações para a parte do valor do nome são quase as mesmas, exceto que o nome não pode começar com $ sign

Tinku
fonte
Onde se diz que os valores devem excluir o sinal de igual na versão 0?
Gili
1

Há outra questão interessante no IE e no Edge. Os cookies que têm nomes com mais de um período parecem ser eliminados silenciosamente. Então, isso funciona:

cookie_name_a = valuea

enquanto isso vai cair

cookie.name.a = valuea

Arvoreen
fonte
Seria ótimo se você adicionar a versão exata do navegador para que possamos replicar, pois o comportamento do navegador não é consistente com os cookies.
Gerald
0

isso é simples:

Um <cookie-name> pode ser qualquer caractere US-ASCII, exceto caracteres de controle (CTLs), espaços ou tabulações. Também não deve conter um caractere separador como o seguinte: () <> @,; : \ "/ []? = {}.

Opcionalmente, um <valor do cookie> pode ser definido entre aspas duplas e quaisquer caracteres US-ASCII, excluindo CTLs, espaço em branco, aspas duplas, vírgula, ponto-e-vírgula e barra invertida são permitidos. Codificação: muitas implementações executam a codificação de URL nos valores dos cookies, mas isso não é exigido pela especificação RFC. No entanto, ajuda a satisfazer os requisitos sobre quais caracteres são permitidos.

Link: https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Headers/Set-Cookie#Directives

webolizzer
fonte
0

Mais uma consideração. Eu recentemente implementei um esquema no qual alguns dados confidenciais postados em um script PHP precisavam convertê-los e devolvê-los como um cookie criptografado, que usava todos os valores base64 que eu achava garantidos como "seguros". Então, criptografei os itens de dados usando RC4, a saída através de base64_encode e retornou o cookie para o site com satisfação. Os testes pareciam ir bem até que uma string codificada em base64 contivesse um símbolo "+". A string foi gravada no cookie da página sem problemas. Usando o diagnóstico do navegador, eu também poderia verifique se os cookies foram gravados inalterados.Em seguida, quando uma página subseqüente chamou meu PHP e obteve o cookie por meio da matriz $ _COOKIE, fiquei impressionado ao descobrir que a string estava com o sinal "+". Cada ocorrência desse caractere foi substituída por um Espaço ASCII.

Considerando-se quantas reclamações semelhantes não resolvidas que li descrevendo esse cenário desde então, muitas vezes colocando numerosas referências ao uso do base64 para armazenar "de forma segura" dados arbitrários em cookies, pensei em apontar o problema e oferecer minha solução confusa.

Depois de fazer a criptografia que você deseja fazer em um pedaço de dados e, em seguida, usar o base64_encode para torná-lo "seguro para cookies", execute a string de saída por este ...

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

Aqui, estou simplesmente substituindo "+" (e decidi "=" também) por outros caracteres "seguros para cookies", antes de retornar o valor codificado para a página, para uso como cookie. Observe que o comprimento da string sendo processada não muda. Quando a mesma (ou outra página do site) executar meu script PHP novamente, poderei recuperar esse cookie sem a falta de caracteres. Eu só tenho que lembrar de passar o cookie de volta pela mesma chamada fix64 () que eu criei, e a partir daí eu posso decodificá-lo com o habitual base64_decode (), seguido por qualquer outra descriptografia no seu esquema.

Pode haver alguma configuração que eu possa fazer no PHP que permita que as strings base64 usadas nos cookies sejam transferidas de volta para o PHP sem corrupção. Enquanto isso, isso funciona. O "+" pode ser um valor de cookie "legal", mas se você deseja transmitir essa string de volta ao PHP (no meu caso através da matriz $ _COOKIE), estou sugerindo um reprocessamento para remover caracteres ofensivos e restaure-os após a recuperação. Existem muitos outros caracteres "seguros para cookies" para você escolher.

Randy
fonte
0

Se você estiver usando as variáveis ​​posteriormente, encontrará coisas como, pathna verdade, permitirão caracteres acentuados, mas na verdade não corresponderá ao caminho do navegador. Para isso, você precisa codificá-los com URI. Então, ou seja, assim:

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

Portanto, os caracteres "permitidos" podem ser mais do que o que está na especificação. Mas você deve permanecer dentro das especificações e usar cadeias codificadas em URI para garantir a segurança.

odinho - Velmont
fonte
-1

Anos atrás, o MSIE 5 ou 5.5 (e provavelmente os dois) teve um problema sério com um "-" no bloco HTML, se você puder acreditar. Embora isso não esteja diretamente relacionado, desde que armazenamos um hash MD5 (contendo apenas letras e números) no cookie para procurar tudo o mais no banco de dados do servidor.

FYA
fonte
-2

Acabei usando

cookie_value = encodeURIComponent(my_string);

e

my_string = decodeURIComponent(cookie_value);

Isso parece funcionar para todos os tipos de personagens. Eu tive problemas estranhos, mesmo com personagens que não eram ponto e vírgula ou vírgulas.

user984003
fonte