Jakie są dozwolone znaki w ciasteczkach?

301

Jakie są dozwolone znaki zarówno w nazwie pliku cookie, jak i wartości? Czy są takie same jak URL lub jakiś wspólny podzbiór?

Powodem, dla którego pytam, jest to, że ostatnio doświadczyłem dziwnego zachowania z plikami cookie, które mają -w ich nazwie i po prostu zastanawiam się, czy jest to coś specyficznego dla przeglądarki lub czy mój kod jest uszkodzony.

Esko
źródło

Odpowiedzi:

391

ten jest szybki:

Możesz myśleć, że tak powinno być, ale tak naprawdę wcale nie jest!

Jakie są dozwolone znaki zarówno w nazwie pliku cookie, jak i wartości?

Według starożytnego Netscape cookie_spec cały NAME=VALUEciąg to:

sekwencja znaków z wyłączeniem średnika, przecinka i białych znaków.

Tak -powinno działać, i wydaje się być OK w przeglądarkach, które tu mam; gdzie masz z tym problem?

Implikując powyższe:

  • =jest to legalne, ale potencjalnie dwuznaczne. Przeglądarki zawsze dzielą nazwę i wartość na pierwszy =symbol w ciągu, więc w praktyce możesz umieścić =symbol w WARTOŚCI, ale nie NAZWĘ.

Co nie jest wspomniane, ponieważ Netscape był okropny w pisaniu specyfikacji, ale wydaje się być konsekwentnie obsługiwany przez przeglądarki:

  • NAZWA lub WARTOŚĆ mogą być pustymi ciągami

  • jeśli =w łańcuchu nie ma żadnego symbolu, przeglądarki traktują go jako plik cookie o nazwie pustego łańcucha, tzn. Set-Cookie: foojest taki sam jak Set-Cookie: =foo.

  • gdy przeglądarki wysyłają plik cookie o pustej nazwie, pomijają znak równości. Więc Set-Cookie: =barzaczyna Cookie: bar.

  • przecinki i spacje w nazwach i wartościach faktycznie działają, chociaż spacje wokół znaku równości są przycięte

  • znaki kontrolne ( \x00na \x1Fplus \x7F) są niedozwolone

To, czego nie wspomniano, a przeglądarki są całkowicie niespójne, to znaki spoza ASCII (Unicode):

  • w Operze i Google Chrome są one kodowane w nagłówkach Cookie za pomocą UTF-8;
  • w IE używana jest domyślna strona kodowa komputera (specyficzna dla ustawień regionalnych i nigdy UTF-8);
  • Firefox (i inne przeglądarki oparte na Mozilli) same używają niskiego bajtu każdego punktu kodowego UTF-16 (więc ISO-8859-1 jest OK, ale wszystko inne jest zniekształcone);
  • Safari po prostu odmawia wysłania pliku cookie zawierającego znaki spoza ASCII.

dlatego w praktyce w plikach cookie nie można w ogóle używać znaków spoza ASCII. Jeśli chcesz korzystać z Unicode, kodów sterujących lub innych dowolnych sekwencji bajtów, cookie_spec wymaga użycia schematu kodowania ad-hoc według własnego wyboru i zasugerowania kodowania URL-a (wyprodukowanego przez JavaScript encodeURIComponent) jako rozsądnego wyboru.

Pod względem faktycznych standardów podjęto kilka prób skodyfikowania zachowania plików cookie, ale jak dotąd żadne nie odzwierciedla rzeczywistego świata.

  • RFC 2109 to próba skodyfikowania i naprawy oryginalnego pliku cookie Netscape. W tym standardzie wiele innych znaków specjalnych jest niedozwolonych, ponieważ używa on tokenów RFC 2616 (a -jest tam nadal dozwolone) i tylko wartość może być określona w cudzysłowie z innymi znakami. Żadna przeglądarka nigdy nie wdrożyła ograniczeń, specjalnej obsługi cytowanych ciągów znaków i znaków zmiany znaczenia ani nowych funkcji w tej specyfikacji.

  • RFC 2965 był kolejnym krokiem w tym kierunku, uporządkując 2109 i dodając więcej funkcji w ramach schematu „ciasteczka w wersji 2”. Nikt też tego nie wdrożył. Ta specyfikacja ma takie same ograniczenia tokenów i cytowanych ciągów jak wcześniejsza wersja i jest to tak samo dużo bzdur.

  • RFC 6265 to próba wyczyszczenia historycznego bałaganu z czasów HTML5. Nadal nie pasuje dokładnie do rzeczywistości, ale jest o wiele lepszy niż wcześniejsze próby - to przynajmniej odpowiedni podzbiór obsługiwanych przeglądarek, nie wprowadzający żadnej składni, która powinna działać, ale nie działa (jak poprzedni ciąg cytowany) .

W 6265 nazwa pliku cookie jest nadal określana jako RFC 2616 token, co oznacza, że ​​możesz wybierać z alfanum plus:

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

W wartości cookie formalnie zakazuje (filtrowane przez przeglądarki) znaki kontrolne i (niekonsekwentnie) znaki spoza ASCII. Zachowuje zakaz cookie_spec dotyczący spacji, przecinków i średników, a także dla zgodności z wszelkimi słabymi idiotami, którzy faktycznie wdrożyli wcześniejsze RFC, zakazał także odwrotnego ukośnika i cytatów, innych niż cytaty zawijające całą wartość (ale w takim przypadku cytaty są nadal uważane za część wartość, a nie schemat kodowania). Dzięki temu masz alfanum plus:

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

W prawdziwym świecie nadal używamy oryginalnego i najgorszego Netscape cookie_spec, więc kod, który zużywa pliki cookie, powinien być przygotowany na prawie wszystko, ale w przypadku kodu, który wytwarza pliki cookie, zaleca się pozostawanie przy podzbiorze w RFC 6265.

Bobin
źródło
@bince Czy masz na myśli, że RFC stwierdza, że ​​wartości plików cookie mogą mieć ;znak, dopóki są otoczone podwójnymi cudzysłowami? Jako taki:Set-Cookie: Name=Va";"lue; Max-Age=3600
Pacerier
@Pacerier: cała wartość musiałaby być ciągiem cytowanym, więc musiałaby być Name="Va;lue"; max-age.... Nie działa w przeglądarkach i jest niedozwolony w RFC 6265, który proponuje się zastąpić 2965 i próbuje nieco lepiej odzwierciedlić rzeczywistość.
Bobin
@ Bobin - Wiem, że jest stary, ale czy poprawnie czytam twoją odpowiedź, co oznacza, że ​​spacje nie są technicznie dozwolone w wartościach plików cookie? „z wyłączeniem średnika, przecinka i białych
znaków
1
@Adam: Tak, jeśli korzystasz ze specyfikacji Netscape lub RFC 6265, białe znaki w surowym (nie DQUOTEd) pliku cookie są niedozwolone. Mimo to działa w przeglądarkach, których wypróbowałem, ale nie polegałbym na tym.
Bobin
2
RFC 6265 definiuje Reklamowe jak 1*<any CHAR except CTLs or separators>i separatory są (, ), <, >, @, ,, ;, :, \, ", /, [, ], ?, =, {, }, SPi HT, więc nazwy plików cookie powinny być alphanums Plus!#$%&'*+-.?^_`|~
Gan Quan
28

W ASP.Net można System.Web.HttpUtilitybezpiecznie zakodować wartość pliku cookie przed zapisaniem go i przekonwertować go z powrotem do oryginalnej postaci po odczytaniu.

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

To zatrzyma znaki handlowe i równe znakom dzielącym wartość na wiązkę par nazwa / wartość, gdy jest zapisywana w pliku cookie.

Stephen
źródło
1
Tylko jedna uwaga, wewnętrznie asp.net używa kodowania szesnastkowego zamiast UrlEncode podczas przechowywania cookie uwierzytelniającego. referenource.microsoft.com # System.Web / Security /… więc mogą zdarzyć się przypadki, w których kod url go nie wyciszy?
Peter
17

Myślę, że ogólnie jest to specyficzne dla przeglądarki. Aby być bezpiecznym, base64 koduje obiekt JSON i zapisuje w nim wszystko. W ten sposób wystarczy go zdekodować i przeanalizować JSON. Wszystkie znaki używane w base64 powinny grać dobrze w większości, jeśli nie we wszystkich przeglądarkach.

Jamie Rumbelow
źródło
Ta odpowiedź wydaje się być spójna w różnych przeglądarkach. Uświadomiłem sobie to po wielu godzinach pracy nad próbą szybkiego rozwiązania: ja też go nie dostałem. Po prostu zrób to, co zalecono dokładnie powyżej, aby uniknąć kłopotów.
uśmiech
Nie próbowałem tego, ale czytałem inne posty o tym powiedzeniu, że kodowanie base64 działa tylko ze znakami ascii.
user984003,
11

Oto, w jak najkrótszych słowach . Skoncentruj się na postaciach, które nie potrzebują ucieczki:

Na ciastka:

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

Dla adresów URL

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

W przypadku plików cookie i adresów URL (skrzyżowanie)

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

Tak odpowiadasz.

Należy pamiętać, że w przypadku plików cookie = zostało usunięte, ponieważ zwykle służy do ustawiania wartości pliku cookie.

W przypadku adresów URL zachowano =. Skrzyżowanie jest oczywiście bez.

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

Okazuje się, że ucieczka wciąż występuje i nieoczekiwane zdarzenie, szczególnie w środowisku plików cookie Java, w którym plik cookie jest zawijany podwójnymi cudzysłowami, jeśli napotka ostatnie znaki.

Aby być bezpiecznym, wystarczy użyć A-Za-z1-9. To właśnie zamierzam zrobić.

mmm
źródło
Pliki cookie Safari były moją jedyną problematyczną przeglądarką - wszystkie inne przeglądarki działały poprawnie. Musiałem UrlEncode i UrlDecode mój plik cookie, aby radzić sobie z znakami równości = i spacjami. Jak kod Base64Encode w pliku cookie. (Safari wymagało tylko tego - inne przeglądarki działały poprawnie z i bez zakodowanego pliku cookie.)
Sql Surfer
Lepiej jest wymienić listę źródeł prowadzących do odpowiedzi!
Loc
1
@Loc Ponad 3 godziny prób i inspekcji.
mmm
10

Nowszy rfc6265 opublikowany w kwietniu 2011 r .:

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

Jeśli spojrzysz na @bobince , zobaczysz, że nowsze ograniczenia są bardziej surowe.

gavenkoa
źródło
6

nie możesz wstawić „;” w polu wartości pliku cookie nazwą, która zostanie ustawiona, jest ciąg znaków do „;” w większości przeglądarek ...

Hagay Onn
źródło
1

Istnieją 2 wersje specyfikacji plików cookie
1. Pliki cookie w wersji 0, czyli ciasteczka Netscape,
2. Pliki cookie, w wersji 1 RFC 2965
W wersji 0 Nazwa i wartość ciasteczek to ciągi znaków, z wyłączeniem średnika, przecinka, znaku równości i białych znaków , jeśli nie jest używana z podwójnymi cudzysłowami,
wersja 1 jest o wiele bardziej skomplikowana, możesz to sprawdzić tutaj
W tej wersji specyfikacja części nazwy wartości jest prawie taka sama, z tym że nazwa nie może zaczynać się od znaku $

Tinku
źródło
Gdzie jest powiedziane, że wartości muszą wykluczać znak równości w wersji 0?
Gili
1

Jest jeszcze jeden interesujący problem z IE i Edge. Pliki cookie o nazwach dłuższych niż 1 okres wydają się po cichu usuwane. To działa:

nazwa_ ciasteczka_a = wartośća

podczas gdy to zostanie porzucone

nazwa pliku cookie. a = wartośća

Arvoreen
źródło
Byłoby wspaniale, jeśli dodasz dokładną wersję przeglądarki, abyśmy mogli się replikować, ponieważ zachowanie przeglądarki nie jest spójne w przypadku plików cookie.
Gerald
0

to proste:

<Nazwa pliku cookie> może być dowolnym znakiem US-ASCII, z wyjątkiem znaków kontrolnych (CTL), spacji lub tabulatorów. Nie może również zawierać znaku separatora, takiego jak: () <> @,; : \ "/ []? = {}.

Opcję <cookie-value> można opcjonalnie ustawić w cudzysłowach i dozwolone są dowolne znaki US-ASCII z wyjątkiem CTL, białych znaków, podwójnych cudzysłowów, przecinków, średników i odwrotnych ukośników. Kodowanie: wiele implementacji wykonuje kodowanie adresów URL na wartościach plików cookie, jednak nie jest to wymagane zgodnie ze specyfikacją RFC. Pomaga jednak spełnić wymagania dotyczące dopuszczalnych postaci.

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

webolizzer
źródło
0

Jeszcze jedna uwaga. Niedawno wdrożyłem schemat, w którym niektóre wrażliwe dane wysłane do skryptu PHP musiały zostać przekonwertowane i zwrócone jako zaszyfrowane ciasteczko, które wykorzystywało wszystkie wartości base64, które moim zdaniem były gwarantowane jako „bezpieczne”. Więc posłusznie zaszyfrowałem elementy danych za pomocą RC4, uruchomiłem dane wyjściowe za pomocą base64_encode i szczęśliwie zwróciły plik cookie na stronę. Testowanie wydawało się przebiegać dobrze, dopóki ciąg zakodowany w standardzie base64 nie zawierał symbolu „+”. Ciąg został zapisany w pliku cookie strony bez żadnych problemów. Korzystając z diagnostyki przeglądarki, mogłem również sprawdź, czy pliki cookie zostały zapisane bez zmian, a następnie, gdy kolejna strona o nazwie mój PHP i uzyskała plik cookie za pomocą tablicy $ _COOKIE, wyjąkałem, że w łańcuchu brakuje teraz znaku „+”. Każde wystąpienie tego znaku zostało zastąpione znakiem Przestrzeń ASCII.

Biorąc pod uwagę, jak wiele podobnych nierozwiązanych skarg przeczytałem opisujących ten scenariusz od tamtej pory, często umieszczając liczne odniesienia do korzystania z base64 do „bezpiecznego” przechowywania dowolnych danych w plikach cookie, pomyślałem, że zwrócę uwagę na problem i zaoferuję moje niechlujne rozwiązanie.

Po wykonaniu dowolnego szyfrowania na kawałku danych, a następnie użyciu base64_encode, aby uczynić go „bezpiecznym dla plików cookie”, uruchom ciąg wyjściowy przez to ...

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

Tutaj po prostu podstawiam „+” (i zdecydowałem również „=”) innymi znakami „bezpiecznymi dla plików cookie”, zanim zwrócę zakodowaną wartość na stronę, do wykorzystania jako plik cookie. Zauważ, że długość przetwarzanego ciągu nie zmienia się. Kiedy ta sama (lub inna strona w witrynie) ponownie uruchomi mój skrypt PHP, będę mógł odzyskać ten plik cookie bez brakujących znaków. Muszę tylko pamiętać, aby przekazać plik cookie z powrotem przez to samo wywołanie fix64 (), które utworzyłem, i stamtąd mogę go zdekodować za pomocą zwykłego base64_decode (), a następnie dowolne inne odszyfrowanie w twoim schemacie.

W PHP może istnieć pewne ustawienie, które pozwala na przesyłanie ciągów base64 używanych w plikach cookie z powrotem do PHP bez uszkodzenia. Tymczasem to działa. „+” Może być „legalną” wartością pliku cookie, ale jeśli masz ochotę móc przesłać taki ciąg znaków z powrotem do PHP (w moim przypadku za pomocą tablicy $ _COOKIE), sugeruję ponowne przetworzenie w celu usunięcia obrażające postacie i przywracaj je po odzyskaniu. Do wyboru jest wiele innych znaków „bezpiecznych dla plików cookie”.

Niespokojny
źródło
0

Jeśli później użyjesz zmiennych, przekonasz się, że takie rzeczy jak pathprzepuszczają znaki akcentowane, ale tak naprawdę nie pasują do ścieżki przeglądarki. W tym celu musisz je URIEncode. Czyli tak:

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

Tak więc „dozwolone” znaki mogą być czymś więcej niż zawartym w specyfikacji. Ale powinieneś pozostać w specyfikacji i używać łańcuchów zakodowanych w URI, aby być bezpiecznym.

odinho - Velmont
źródło
-1

Wiele lat temu MSIE 5 lub 5.5 (i prawdopodobnie oba) miały poważny problem z „-” w bloku HTML, jeśli możesz w to uwierzyć. Chociaż nie jest to bezpośrednio powiązane, odkąd przechowujemy skrót MD5 (zawierający tylko litery i cyfry) w pliku cookie, aby wyszukać wszystko inne w bazie danych po stronie serwera.

FYA
źródło
-2

Skończyło się na tym

cookie_value = encodeURIComponent(my_string);

i

my_string = decodeURIComponent(cookie_value);

Wydaje się, że działa to na wszystkie postacie. Poza tym miałem dziwne problemy, nawet z postaciami, które nie były średnikami ani przecinkami.

użytkownik984003
źródło