Які дозволені символи у файлах cookie?


301

Які дозволені символи мають і ім’я файлу cookie, і значення? Вони такі ж, як URL-адреса чи якесь загальне підмножина?

Причина, про яку я прошу, - це те, що я нещодавно стикався з якоюсь дивною поведінкою у файлах cookie, які є -в їхньому імені, і мені просто цікаво, чи це щось конкретно для браузера чи чи мій код несправний.

Відповіді:


391

це швидке:

Ви можете подумати, що має бути, але насправді це зовсім не так!

Які дозволені символи мають і ім’я файлу cookie, і значення?

Відповідно до стародавнього cookie_spec Netscape, весь NAME=VALUEрядок:

послідовність символів, що виключає крапки з комою, комою та пробілом.

Так -має працювати, і, схоже, це добре в браузерах, у яких я потрапив сюди; де у вас проблеми?

Під впливом вищезазначеного:

  • =є законним, але потенційно неоднозначним. Браузери завжди розділяють ім'я та значення на першому =символі в рядку, тому на практиці ви можете помістити =символ у значення "VALUE", а не "NAME".

Що не згадується, оскільки Netscape був жахливим при написанні специфікацій, але, схоже, підтримується браузерами:

  • або NAME, або VALUE можуть бути порожніми рядками

  • якщо =символу в рядку немає взагалі, браузери розглядають його як печиво з назвою порожнього рядка, тобто Set-Cookie: fooтаке ж, як Set-Cookie: =foo.

  • коли браузери видають печиво з порожнім ім'ям, вони опускають знак рівності. Так і Set-Cookie: =barпочинається Cookie: bar.

  • коми і пробіли в іменах та значеннях насправді, здається, працюють, хоча пробіли навколо знака рівності оброблені

  • контрольні символи ( \x00до \x1Fплюс \x7F) заборонені

Те, що не згадується, і браузери абсолютно непослідовні, це символи, що не належать до ASCII (Unicode):

  • в Opera та Google Chrome вони кодуються до заголовків Cookie з UTF-8;
  • в IE використовується сторінка коду за замовчуванням машини (специфічна для локального типу та ніколи не UTF-8);
  • Firefox (та інші браузери на базі Mozilla) використовують низький байт кожної кодової точки UTF-16 самостійно (тому ISO-8859-1 добре, але все інше налаштовано);
  • Safari просто відмовляється надсилати файли cookie, що містять символи, що не належать до ASCII.

тому на практиці ви взагалі не можете використовувати символи, що не належать до ASCII. Якщо ви хочете використовувати Unicode, контрольні коди або інші довільні байтові послідовності, cookie_spec вимагає використовувати спеціальну схему кодування за власним вибором і запропонувати кодування URL (як вироблено JavaScript encodeURIComponent) як розумний вибір.

Що стосується фактичних стандартів, то було декілька спроб кодифікувати поведінку файлів cookie, але жодна поки що насправді не відображає реальний світ.

  • RFC 2109 була спробою кодифікувати та виправити оригінальний файл cookie_spec Netscape. У цьому стандарті багато інших спеціальних символів заборонені, оскільки в ньому використовуються RFC 2616 лексеми (a -все ще дозволено там), і лише значення може бути вказане в рядку з цитатами з іншими символами. Жоден веб-переглядач ніколи не реалізовував обмежень, спеціального поводження з цитованими рядками та скачуванням або нових функцій у цій специфікації.

  • RFC 2965 - це ще одна робота, прибираючи 2109 та додаючи додаткові можливості за схемою "cookie версії 2". Ніхто ніколи цього не реалізував. Ця специфікація має ті ж обмеження, що цитуються на основі лексем і цитувань, як і в попередній версії, і це так само велика кількість дурниць.

  • RFC 6265 - це спроба епохи HTML5 очистити історичний безлад. Він все ще не відповідає дійсності, але набагато краще, ніж попередні спроби - це принаймні належний підмножина того, що підтримують браузери, не вводячи жодного синтаксису, який повинен працювати, але не працює (як попередній цитуваний рядок) .

У 6265 році ім'я файлу cookie все ще вказано як RFC 2616 token, що означає, що ви можете вибрати з літер плюс:

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

У значенні cookie він формально забороняє (відфільтровані браузерами) контрольні символи та (непослідовно реалізовані) символи, що не належать до ASCII. Він зберігає заборону cookie_spec на простір, кому та крапку з комою, а також на сумісність з будь-якими бідними ідіотами, які фактично реалізували попередні RFC, він також заборонив зворотну косу рису та котирування, крім цитат, що містять ціле значення (але в цьому випадку цитати досі вважаються частиною значення, а не схема кодування). Таким чином, це залишає вам літери плюс:

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

У реальному світі ми все ще використовуємо оригінальний і найгірший Netscape cookie_spec, тому код, який споживає файли cookie, повинен бути готовий зустріти майже все, але для коду, який створює файли cookie, бажано дотримуватися підмножини в RFC 6265.


@bobince Ви маєте на увазі, що RFC стверджує, що значення файлів cookie можуть мати ;характер, якщо вони оточені подвійними лапками? Як таке:Set-Cookie: Name=Va";"lue; Max-Age=3600
Pacerier

@Pacerier: все значення повинно бути котированим рядком, тому воно повинно бути Name="Va;lue"; max-age.... Він не працює в браузерах, і це не дозволено в RFC 6265, який пропонується замінити 2965 і намагається трохи краще відобразити реальність.
bobince

@bobince - я знаю, що це давнє, але чи я правильно читаю вашу відповідь, щоб означати, що пробіли технічно не дозволені у значеннях файлів cookie? "без урахування
крапки з

1
@Adam: Так, якщо ви збираєтеся за специфікацією Netscape або RFC 6265, пробіл не дозволений у сирому (un-DQUOTEd) значенні файлу cookie. Тим не менш, це працює в браузерах, які я спробував, але я б не покладався на нього.
bobince

2
RFC 6265 визначає лексем як 1*<any CHAR except CTLs or separators>і сепаратори (, ), <, >, @, ,, ;, :, \, ", /, [, ], ?, =, {, }, SPі HT, тому імена печива повинні бути alphanums плюс!#$%&'*+-.?^_`|~
Gan Quan

28

У ASP.Net ви можете System.Web.HttpUtilityбезпечно кодувати значення файлу cookie перед написанням на файл cookie та перетворити його в початковий вигляд, прочитавши його.

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

Це зупинить розширення і дорівнює знакам, що розбивають значення на купу імен / значень пар, як це записано в cookie.


1
Лише одна примітка: asp.net внутрішньо використовує шістнадцяткове кодування замість UrlEncode при зберіганні файлу cookie автентифікації. referenceource.microsoft.com # System.Web / Security /… тож можуть бути випадки, коли кодування URL-адреси не вирізає?
Петро

17

Я думаю, що це, як правило, специфічно для браузера. Щоб бути на безпечній стороні, base64 кодує JSON-об'єкт і зберігає все в цьому. Таким чином, вам просто потрібно розшифрувати його та проаналізувати JSON. Усі символи, які використовуються в base64, повинні чудово грати з більшістю, якщо не з усіма браузерами.


Ця відповідь, здається, є послідовною у веб-переглядачах. Я зрозумів це, працюючи багато годин, намагаючись швидше вирішити: я теж не отримав. Просто зробіть, як рекомендовано саме вище, щоб уберегти себе від клопотів.
посмішка

Не пробував цього, але я читав інші публікації з цього приводу, що кодування base64 працює лише з символами ascii.
user984003

11

Ось воно, якомога менше слів . Зосередьтеся на персонажах, яким не потрібно бігти:

Для печива:

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

Для URL-адрес

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

Для файлів cookie та URL-адрес (перетину)

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

Ось як ви відповідаєте.

Зауважте, що для файлів cookie значення = було видалено, оскільки воно зазвичай використовується для встановлення значення файлу cookie.

Для URL-адрес це збережено =. Перехрестя, очевидно, без.

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

Виявляється, все ще виникає і несподіване трапляється, особливо в середовищі файлів cookie Java, де файл cookie обгортається подвійними лапки, якщо він стикається з останніми символами.

Отже, щоб бути безпечним, просто використовуйте A-Za-z1-9. Ось що я збираюся робити.


Safari Cookies були моєю єдиною проблемою в браузері - всі інші браузери працювали чудово. Мені довелося UrlEncode і UrlDecode мій файл cookie, щоб мати справу з знаками рівності = та пробілами. Як Base64Encode у файлі cookie. (Сафарі вимагав лише цього - інші браузери чудово працювали з кодованим файлом cookie та без нього.)
Sql Surfer

Краще, якщо ви перерахуєте, які джерела ведуть до вашої відповіді!
Лок

1
@Loc Більше 3-х годин випробувань та перевірок.
ммм

10

Новіший rfc6265 опублікований у квітні 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

Якщо ви подивитесь на відповідь @bobince, ви побачите, що нові обмеження суворіші .


6

не можна ставити ";" у полі значень файлу cookie ім'я, яке буде встановлено, є рядком до ";" у більшості браузерів ...


1

Існує 2 версії специфікацій cookie
1. Версія 0 cookies aka Netscape cookies,
2. Версія 1 aka RFC 2965 cookies
У версії 0 Ім'я та значення файлів cookie є послідовностями символів, виключаючи крапку з комою, комою, знаком рівності та пробілом , якщо не використовується в подвійних лапках ,
версія 1 є набагато більш складним , ви можете перевірити його тут
в цій версії специфікації для значення імені частині майже те ж саме , крім імені не може починатися з знаком $


Звідки йдеться про те, що значення повинні виключати знак рівності у версії 0?
Гілі

1

Є ще одна цікава проблема з IE та Edge. Файли cookie, які мають назви більше 1 періоду, здаються, мовчки скидаються. Так це працює:

cookie_name_a = valuea

поки це знизиться

cookie.name.a = valuea


Було б чудово, якщо ви додасте точну версію браузера для того, щоб ми реплікували, оскільки поведінка браузера не узгоджується з файлами cookie.
Джеральд

0

це просто:

<Ім'я_кокія> може бути будь-якими символами US-ASCII, крім контрольних символів (CTL), пробілів або вкладок. Він також не повинен містити символу роздільника на зразок наступного: () <> @,; : \ "/ []? = {}.

<cookie-value> необов'язково може бути встановлено у подвійних лапках, а будь-які символи US-ASCII, за винятком CTL, пробілів, подвійних лапок, кома, крапки з комою та зворотньої коси, дозволені. Кодування: Багато реалізацій виконують кодування URL за значеннями файлів cookie, однак це не потрібно в специфікації RFC. Це допомагає задовольняти вимоги, щодо яких символів дозволено хоча.

Посилання: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Directives


0

Ще один розгляд. Нещодавно я реалізував схему, в якій деякі конфіденційні дані, розміщені у скрипті PHP, необхідні для перетворення та повернення їх у вигляді зашифрованого файлу cookie, в якому використовувались всі базові значення 64, які, на мою думку, були гарантовані "безпечними". Тому я гідно зашифрував елементи даних за допомогою RC4, побіг виведення через base64_encode, і щасливо повернув файл cookie на сайт. Тестування, здавалося, пройшло добре, поки в кодованій рядку base64 не було символу "+". Рядок був записаний на файл cookie сторінки без проблем. Використовуючи діагностику браузера, я також міг Перевірте, чи файли cookie були написані незмінними. Потім, коли наступна сторінка викликала мій PHP і отримала файл cookie через масив $ _COOKIE, я був замурований, щоб виявити, що в рядку відсутній знак "+". Кожне виникнення цього символу замінювалося на Простір ASCII.

Зважаючи на те, скільки подібних невирішених скарг я читав описуючи цей сценарій з тих пір, часто розміщуючи численні посилання на використання base64 для "безпечного" зберігання довільних даних у файлах cookie, я подумав, що я зазначу проблему і запропоную своє, безумовно, невдале рішення.

Після того, як ви зробили будь-яке шифрування, яке ви хочете зробити на фрагменті даних, а потім використали base64_encode, щоб зробити його "безпечним для файлів cookie", запустіть вихідний рядок через це ...

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

Тут я просто підміняю "+" (і я вирішив "=" також) іншими символами "безпечного для файлів cookie", перш ніж повертати закодоване значення на сторінку, для використання в якості файлу cookie. Зауважте, що довжина оброблюваної нитки не змінюється. Коли ця ж (або інша сторінка на сайті) знову запустить мій скрипт PHP, я зможу відновити це файли cookie без пропущених символів. Мені просто потрібно пам’ятати, щоб повернути файл cookie через той самий виклик fix64 (), який я створив, і звідти я можу розшифрувати його за допомогою звичайного base64_decode () з подальшим будь-яким іншим розшифруванням у вашій схемі.

У PHP може бути якесь налаштування, яке дозволяє передавати рядки base64, які використовуються в файлах cookie, до PHP без пошкодження. Тим часом це працює. Значення "+" може бути "законним" файлом cookie, але якщо у вас є бажання мати можливість передавати такий рядок назад до PHP (у моєму випадку через масив $ _COOKIE), я пропоную повторну обробку для видалення ображаючи символів, і відновити їх після відновлення. Існує велика кількість інших персонажів, захищених від файлів cookie.


0

Якщо ви будете використовувати змінні пізніше, ви знайдете, що такі речі, як pathнасправді, пропускатимуть наголошені символи, але вони насправді не відповідають шляху браузера. Для цього вам потрібно URIEncode їх. Так ось так:

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

Тож "дозволені" символи можуть бути більше, ніж у специфікації. Але вам слід залишатися в межах специфікації та використовувати рядки, кодовані URI, для безпечності.


-1

Роки тому MSIE 5 або 5.5 (і, мабуть, обидва) мали серйозні проблеми з "-" в блоці HTML, якщо ви можете в це повірити. Хоча це не пов’язано безпосередньо, оскільки ми зберігаємо в файлі cookie хеш MD5 (містить лише букви та цифри), щоб шукати все інше в базі даних сервера.


-2

Я закінчив використовувати

cookie_value = encodeURIComponent(my_string);

і

my_string = decodeURIComponent(cookie_value);

Це, здається, працює для всіх видів персонажів. Інакше у мене були дивні проблеми, навіть із символами, які не були крапками з комою чи комами.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.