Quali sono i caratteri consentiti nei cookie?


301

Quali sono i caratteri consentiti sia nel nome che nel valore del cookie? Sono gli stessi dell'URL o di alcuni sottoinsiemi comuni?

Il motivo che sto chiedendo è che di recente ho riscontrato un comportamento strano con i cookie che hanno -nel loro nome e mi chiedo solo se è qualcosa di specifico del browser o se il mio codice è difettoso.

Risposte:


391

questa è una sveltina:

Potresti pensare che dovrebbe essere, ma in realtà non lo è affatto!

Quali sono i caratteri consentiti sia nel nome che nel valore del cookie?

Secondo l'antica Netscape cookie_spec l'intera NAME=VALUEstringa è:

una sequenza di caratteri esclusi punti e virgola, virgola e spazi bianchi.

Quindi -dovrebbe funzionare, e sembra essere OK nei browser che ho qui; dove hai problemi con esso?

Come conseguenza di quanto sopra:

  • =è legale includere, ma potenzialmente ambiguo. I browser dividono sempre il nome e il valore sul primo =simbolo nella stringa, quindi in pratica puoi inserire un =simbolo in VALUE ma non in NAME.

Ciò che non è menzionato, perché Netscape è stato terribile nello scrivere le specifiche, ma sembra essere costantemente supportato dai browser:

  • NAME o VALUE possono essere stringhe vuote

  • se =nella stringa non è presente alcun simbolo, i browser lo trattano come il cookie con il nome della stringa vuota, ovvero Set-Cookie: fooè uguale a Set-Cookie: =foo.

  • quando i browser generano un cookie con un nome vuoto, omettono il segno di uguale. Quindi Set-Cookie: =bargenera Cookie: bar.

  • le virgole e gli spazi nei nomi e nei valori sembrano effettivamente funzionare, sebbene gli spazi attorno al segno di uguale siano tagliati

  • i caratteri di controllo ( \x00a \x1Fpiù \x7F) non sono ammessi

Ciò che non è menzionato e i browser sono totalmente incoerenti, sono i caratteri non ASCII (Unicode):

  • in Opera e Google Chrome, sono codificati nelle intestazioni dei cookie con UTF-8;
  • in IE, viene utilizzata la tabella codici predefinita della macchina (specifica della locale e mai UTF-8);
  • Firefox (e altri browser basati su Mozilla) usano il byte basso di ogni punto di codice UTF-16 da solo (quindi ISO-8859-1 è OK ma tutto il resto è alterato);
  • Safari si rifiuta semplicemente di inviare qualsiasi cookie contenente caratteri non ASCII.

quindi in pratica non è possibile utilizzare caratteri non ASCII nei cookie. Se si desidera utilizzare Unicode, codici di controllo o altre sequenze di byte arbitrarie, cookie_spec richiede di utilizzare uno schema di codifica ad hoc di propria scelta e di suggerire la codifica URL (come prodotta da JavaScript encodeURIComponent) come scelta ragionevole.

In termini di standard effettivi , ci sono stati alcuni tentativi di codificare il comportamento dei cookie, ma nessuno finora riflette effettivamente il mondo reale.

  • RFC 2109 era un tentativo di codificare e correggere l'originale cookie_spec di Netscape. In questo standard sono vietati molti altri caratteri speciali, in quanto utilizza token RFC 2616 (a -è ancora consentito lì) e solo il valore può essere specificato in una stringa tra virgolette con altri caratteri. Nessun browser ha mai implementato i limiti, la gestione speciale di stringhe e escape quotati o le nuove funzionalità di questa specifica.

  • RFC 2965 è stato un altro tentativo, riordinando il 2109 e aggiungendo ulteriori funzionalità in uno schema di "versione 2 cookie". Nemmeno nessuno lo ha mai implementato. Questa specifica ha le stesse limitazioni di token e quoted string della versione precedente ed è altrettanto un carico di sciocchezze.

  • RFC 6265 è un tentativo dell'era HTML5 di chiarire il disordine storico. Non corrisponde ancora esattamente alla realtà, ma è molto meglio dei tentativi precedenti: è almeno un sottoinsieme corretto di ciò che supporta il browser, non introducendo alcuna sintassi che dovrebbe funzionare ma non funziona (come la stringa tra virgolette precedente) .

Nel 6265 il nome del cookie è ancora specificato come RFC 2616 token, il che significa che è possibile scegliere tra gli alfani più:

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

Nel valore del cookie vieta formalmente i caratteri di controllo (filtrati dai browser) e i caratteri non ASCII (implementati in modo incoerente). Mantiene il divieto di cookie_spec su spazio, virgola e punto e virgola, oltre alla compatibilità con eventuali poveri idioti che hanno effettivamente implementato i precedenti RFC, ha anche vietato barre rovesciate e virgolette, oltre alle virgolette che racchiudono l'intero valore (ma in quel caso le virgolette sono ancora considerate parte di il valore, non uno schema di codifica). In modo che ti lascia con gli alfani più:

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

Nel mondo reale stiamo ancora usando il cookie_spec Netscape originale e peggiore, quindi il codice che consuma i cookie dovrebbe essere preparato per incontrare praticamente qualsiasi cosa, ma per il codice che produce i cookie è consigliabile attenersi al sottoinsieme in RFC 6265.


@bobince Intendi che la RFC afferma che i valori dei cookie possono avere il ;carattere purché sia ​​racchiuso tra virgolette? Come tale:Set-Cookie: Name=Va";"lue; Max-Age=3600
Pacerier

@Pacerier: l'intero valore dovrebbe essere una stringa tra virgolette, quindi dovrebbe essere Name="Va;lue"; max-age.... Non funziona nei browser e non è consentito in RFC 6265, che si propone di sostituire 2965 e cerca di riflettere un po 'meglio la realtà.
Bobince,

@bobince - So che è vecchio, ma sto leggendo la tua risposta correttamente per indicare che gli spazi non sono tecnicamente ammessi nei valori dei cookie? "esclusi i punti e virgola, la virgola e lo spazio bianco " [enfasi sulla mia]
Adam Rackis,

1
@Adam: Sì, se stai seguendo le specifiche Netscape o RFC 6265, gli spazi bianchi non sono consentiti in un valore di cookie grezzo (non DQUOTEd). Funziona comunque nei browser che ho provato, ma non mi affiderei.
bobince l'

2
RFC 6265 definisce come Token 1*<any CHAR except CTLs or separators>e separatori sono (, ), <, >, @, ,, ;, :, \, ", /, [, ], ?, =, {, }, SPe HT, quindi nomi dei cookie dovrebbero essere alphanums più!#$%&'*+-.?^_`|~
Gan Quan

28

In ASP.Net è possibile utilizzare System.Web.HttpUtilityper codificare in modo sicuro il valore del cookie prima di scriverlo e convertirlo nella sua forma originale dopo averlo letto.

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

Ciò interromperà la e commerciale e sarà uguale ai segni che dividono un valore in un gruppo di coppie nome / valore mentre viene scritto in un cookie.


1
Solo una nota, internamente asp.net utilizza la codifica esadecimale invece di UrlEncode durante la memorizzazione del cookie di autenticazione. referenceource.microsoft.com # System.Web / Security / ... quindi potrebbero esserci dei casi in cui la codifica dell'URL non la taglierà?
Peter,

17

Penso che sia generalmente specifico del browser. Per essere al sicuro, base64 codifica un oggetto JSON e archivia tutto in quello. In questo modo devi solo decodificarlo e analizzare il JSON. Tutti i personaggi usati in base64 dovrebbero giocare bene con la maggior parte, se non con tutti i browser.


Questa risposta sembra essere coerente tra i browser. Me ne sono reso conto dopo aver lavorato molte ore cercando di ottenere una soluzione rapida: non ne avevo nemmeno una. Fai come raccomandato esattamente sopra per salvarti le seccature.
sorridi l'

Non ho provato questo, ma ho letto altri post su questo dicendo che la codifica base64 funziona solo con caratteri ASCII.
user984003

11

Eccolo qui, nel minor numero di parole possibile . Concentrati sui personaggi che non hanno bisogno di fuggire:

Per i biscotti:

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

Per gli URL

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

Per cookie e URL (intersezione)

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

Ecco come rispondi.

Si noti che per i cookie, il = è stato rimosso perché di solito viene utilizzato per impostare il valore del cookie.

Per url questo è stato mantenuto il =. L'intersezione è ovviamente senza.

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

Risulta che sfuggono ancora e si verificano inaspettati, specialmente in un ambiente di cookie Java in cui il cookie viene racchiuso tra virgolette se incontra gli ultimi caratteri.

Quindi, per sicurezza, basta usare A-Za-z1-9. Questo è quello che ho intenzione di fare.


I cookie di Safari erano il mio unico problema: tutti gli altri browser funzionavano bene. Ho dovuto UrlEncode e UrlDecode il mio cookie per gestire uguale = segni e spazi. Come un codice Base64 nel cookie. (Safari richiede solo questo- altri browser hanno funzionato bene con e senza il cookie codificato.)
Sql Surfer

È meglio se elenchi quali fonti portano alla tua risposta!
Loc

1
@Loc Oltre 3 ore di prova e ispezione.
mmm

10

La più recente rfc6265 pubblicata nell'aprile 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 guardi @bobince rispondi, vedi che le restrizioni più recenti sono più severe.


6

non puoi mettere ";" nel campo valore di un cookie, il nome che verrà impostato è la stringa fino a ";" nella maggior parte dei browser ...


1

Esistono 2 versioni delle specifiche dei cookie
1. Cookie versione 0 noti anche come cookie Netscape,
2. Versione 1 noti anche come cookie RFC 2965
Nella versione 0 La parte nome e valore dei cookie sono sequenze di caratteri, esclusi il punto e virgola, la virgola, il segno di uguale e lo spazio bianco , se non utilizzato con virgolette doppie la
versione 1 è molto più complicata, puoi verificarla qui
In questa versione le specifiche per la parte valore nome è quasi la stessa, tranne il nome non può iniziare con $ segno


Dove dice che i valori devono escludere equals accedi alla versione 0?
Gili,

1

C'è un altro problema interessante con IE e Edge. I cookie che hanno nomi con più di 1 periodo sembrano essere eliminati silenziosamente. Quindi funziona:

cookie_name_a = valoreA

mentre questo verrà eliminato

cookie.name.a = valoreA


Sarebbe bello se aggiungessi la versione esatta del browser per consentirci di replicare, poiché il comportamento del browser non è coerente con i cookie.
Gerald,

0

è semplice:

Un <cookie-name> può essere qualsiasi carattere US-ASCII eccetto i caratteri di controllo (CTL), gli spazi o le schede. Inoltre, non deve contenere un carattere separatore come il seguente: () <> @,; : \ "/ []? = {}.

Un <cookie-value> può essere impostato facoltativamente tra virgolette doppie e sono ammessi tutti i caratteri US-ASCII esclusi CTL, spazi bianchi, virgolette doppie, virgola, punto e virgola e barra rovesciata. Codifica: molte implementazioni eseguono la codifica URL sui valori dei cookie, tuttavia non è richiesto dalle specifiche RFC. Aiuta a soddisfare i requisiti per i quali sono ammessi i personaggi.

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


0

Un'altra considerazione. Di recente ho implementato uno schema in cui alcuni dati sensibili pubblicati in uno script PHP dovevano convertirli e restituirli come cookie crittografato, che utilizzava tutti i valori base64 che ritenevo garantiti "sicuri". Quindi ho crittografato debitamente gli elementi di dati utilizzando RC4, l'output tramite base64_encode e restituito felicemente il cookie al sito. I test sembravano andare bene fino a quando una stringa codificata in base64 non conteneva un simbolo "+". La stringa è stata scritta sul cookie della pagina senza problemi. Utilizzando la diagnostica del browser ho potuto anche verifica che i cookie siano stati scritti invariati, quindi quando una pagina successiva ha chiamato il mio PHP e ha ottenuto il cookie tramite l'array $ _COOKIE, sono rimasto sorpreso nel constatare che nella stringa mancava il segno "+". Ogni ricorrenza di quel carattere veniva sostituita con un Spazio ASCII.

Considerando quante lamentele simili non risolte che ho letto descrivendo questo scenario da allora, trovando spesso numerosi riferimenti all'utilizzo di base64 per archiviare "in modo sicuro" dati arbitrari nei cookie, ho pensato di evidenziare il problema e di offrire la mia soluzione ammessa kludgy.

Dopo aver eseguito la crittografia che desideri eseguire su un dato e dopo aver utilizzato base64_encode per renderlo "sicuro per i cookie", esegui la stringa di output attraverso questo ...

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

Qui sto semplicemente sostituendo "+" (e ho deciso anche "=") con altri caratteri "sicuri per i cookie", prima di restituire il valore codificato alla pagina, da utilizzare come cookie. Si noti che la lunghezza della stringa in elaborazione non cambia. Quando la stessa (o un'altra pagina del sito) esegue nuovamente il mio script PHP, sarò in grado di recuperare questo cookie senza caratteri mancanti. Devo solo ricordare di passare il cookie indietro attraverso la stessa chiamata fix64 () che ho creato, e da lì posso decodificarlo con il solito base64_decode (), seguito da qualunque altra decrittazione nel tuo schema.

Potrebbero esserci alcune impostazioni che potrei fare in PHP che consentono alle stringhe base64 utilizzate nei cookie di essere trasferite a PHP senza corruzione. Nel frattempo funziona. Il "+" può essere un valore "legale" per i cookie, ma se si desidera poter ritrasmettere una tale stringa a PHP (nel mio caso tramite l'array $ _COOKIE), sto suggerendo di rielaborare per rimuovere personaggi offensivi e ripristinarli dopo il recupero. Ci sono molti altri personaggi "sicuri per i cookie" tra cui scegliere.


0

Se in seguito utilizzerai le variabili, scoprirai che cose come patheffettivamente lasceranno passare i caratteri accentati, ma in realtà non corrisponderanno al percorso del browser. Per questo è necessario URIEncode. Quindi vale a dire così:

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

Quindi i caratteri "consentiti" potrebbero essere più di quanto specificato nelle specifiche. Ma dovresti rimanere all'interno delle specifiche e usare le stringhe con codifica URI per sicurezza.


-1

Anni fa MSIE 5 o 5.5 (e probabilmente entrambi) hanno avuto seri problemi con un "-" nel blocco HTML se ci credi. Anche se non è direttamente correlato, da quando abbiamo memorizzato un hash MD5 (contenente solo lettere e numeri) nel cookie per cercare tutto il resto nel database lato server.


-2

Ho finito per usare

cookie_value = encodeURIComponent(my_string);

e

my_string = decodeURIComponent(cookie_value);

Sembra funzionare per tutti i tipi di personaggi. Ho avuto strani problemi altrimenti, anche con personaggi che non erano punti e virgola o virgole.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.