Какие разрешенные символы в куки?


301

Каковы допустимые символы в имени и значении файла cookie? Они такие же, как URL или какое-то общее подмножество?

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

Ответы:


391

это быстрый

Вы можете подумать, что так и должно быть, но на самом деле это совсем не так!

Каковы допустимые символы в имени и значении файла cookie?

Согласно древнему Netscape cookie_spec, вся NAME=VALUEстрока выглядит так:

последовательность символов, исключая точку с запятой, запятую и пробел.

Так -должно работать, и, похоже, все в порядке в браузерах, которые у меня здесь есть; где у вас проблемы с этим?

Подразумевается вышеизложенное:

  • =законно включить, но потенциально неоднозначно. Браузеры всегда разделяют имя и значение по первому =символу в строке, поэтому на практике вы можете поместить =символ в VALUE, но не в NAME.

Что не упомянуто, потому что Netscape были ужасны в написании спецификаций, но, похоже, постоянно поддерживаются браузерами:

  • ИМЯ или ЗНАЧЕНИЕ могут быть пустыми строками

  • если =в строке вообще нет символа, браузеры обрабатывают его как файл cookie с именем пустой строки, то 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 был попыткой кодификации и исправления оригинального Netscape cookie_spec. В этом стандарте многих других специальных символов запрещены, так как он использует RFC 2616 маркеров (а -это по- прежнему разрешено там), и только значение может быть указано в кавычках струны с другими персонажами. Ни один браузер никогда не реализовывал ограничения, специальную обработку строк в кавычках и экранирование или новые функции в этой спецификации.

  • RFC 2965 был еще одним шагом, прибравшим 2109 и добавляющим больше возможностей по схеме «куки версии 2». Никто никогда не реализовывал ничего из этого. Эта спецификация имеет те же ограничения по токенам и кавычкам, что и в предыдущей версии, и это такая же ерунда.

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

В 6265 имя cookie по-прежнему указывается как RFC 2616 token, что означает, что вы можете выбрать из алфавитов плюс:

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

В значении cookie он формально запрещает (отфильтрованные браузерами) управляющие символы и (непоследовательно реализованные) не-ASCII символы. Он сохраняет запрет cookie_spec на пробел, запятую и точку с запятой, плюс для совместимости с любыми плохими идиотами, которые фактически реализовали более ранние RFC, он также запретил обратную косую черту и кавычки, кроме кавычек, охватывающих все значение (но в этом случае кавычки все еще считаются частью значение, а не схема кодирования). Так что это оставляет вас с alphanums плюс:

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

В реальном мире мы все еще используем исходный и худший Netscape cookie_spec, поэтому код, который использует куки, должен быть готов встретить практически все, но для кода, который генерирует куки, рекомендуется придерживаться подмножества в RFC 6265.


@bobince Вы имеете в виду, что в RFC говорится, что значения cookie могут иметь ;символ, если он заключен в двойные кавычки? Как таковой:Set-Cookie: Name=Va";"lue; Max-Age=3600
Pacerier

@Pacerier: все значение должно быть строкой в ​​кавычках, поэтому оно должно быть Name="Va;lue"; max-age.... Он не работает в браузерах и не разрешен в RFC 6265, который предлагается заменить 2965 и пытается немного лучше отражать реальность.
бобинце

@bobince - я знаю, что это старый, но правильно ли я читаю ваш ответ, чтобы обозначить, что в значениях cookie технически не разрешены пробелы? «исключая
точку с

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

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 при хранении куки-файла аутентификации. referenceource.microsoft.com # System.Web / Security /… так что, может быть, в некоторых случаях кодирование URL не обрезает его?
Питер

17

Я думаю, что это в целом зависит от браузера. Чтобы быть в безопасности, base64 кодирует объект JSON и сохраняет все в нем. Таким образом, вы просто должны декодировать его и проанализировать JSON. Все символы, используемые в base64, должны хорошо работать с большинством, если не со всеми браузерами.


Этот ответ, кажется, является согласованным во всех браузерах. Я понял это после многих часов работы, пытаясь найти быстрое решение: я тоже не получил. Просто сделайте, как указано выше, чтобы избежать неприятностей.
улыбка

Не пробовал, но я читал другие посты об этом, говоря, что base64-кодирование работает только с символами ascii.
user984003

11

Вот оно, как можно меньше слов . Сосредоточьтесь на персонажах, которым не нужно убегать:

Для печенья:

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

Для URL

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

Для печенья и 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. (Safari требуется только это - другие браузеры работали нормально с и без закодированного 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. Файлы cookie версии 0, также известные как файлы cookie Netscape,
2. Файлы cookie версии 1, также известные как RFC 2965.
В версии 0 Часть файлов cookie с именами и значениями представляет собой последовательности символов, исключая точку с запятой, запятую, знак равенства и пробелы. , если не используется с двойными кавычками,
версия 1 намного сложнее, вы можете проверить это здесь.
В этой версии спецификации для значения имени почти одинаковы, за исключением того, что имя не может начинаться со знака $


Где сказано, что значения должны исключать знак равенства в версии 0?
Гили

1

Есть еще одна интересная проблема с IE и Edge. Файлы cookie с именами более 1 периода, по-видимому, молча отбрасываются. Так что это работает:

cookie_name_a = значение а

пока это упадет

cookie.name.a = значение а


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

0

это просто:

<Cookie-name> может быть любым символом US-ASCII, кроме управляющих символов (CTL), пробелов или символов табуляции. Он также не должен содержать символ-разделитель, например: () <> @,; знак равно

<Cookie-значение> может быть необязательно установлено в двойных кавычках, и любые символы US-ASCII, за исключением CTL, пробелов, двойных кавычек, запятой, точки с запятой и обратной косой черты, допускаются. Кодировка. Многие реализации выполняют кодирование URL-адресов для значений файлов cookie, однако это не требуется согласно спецификации RFC. Это помогает удовлетворить требования о том, какие символы разрешены.

Ссылка: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Directives


0

Еще одно соображение. Недавно я реализовал схему, в которой некоторые конфиденциальные данные, публикуемые в сценарии PHP, должны были преобразовываться и возвращаться в виде зашифрованного файла cookie, в котором использовались все значения base64, которые я считал гарантированно «безопасными». Поэтому я должным образом зашифровал элементы данных с помощью 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), я предлагаю повторную обработку для удаления оскорблять персонажей и восстанавливать их после восстановления. Есть множество других «безопасных от печенья» символов на выбор.


0

Если вы позже будете использовать переменные, вы обнаружите, что такие вещи, как на pathсамом деле, пропускают акцентированные символы, но на самом деле они не соответствуют пути браузера. Для этого вам нужно URIEncode их. Итак, вот так:

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

Таким образом, «разрешенные» символы могут быть больше, чем в спецификации. Но вы должны оставаться в пределах спецификации и использовать строки в кодировке URI для безопасности.


-1

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


-2

Я в конечном итоге с помощью

cookie_value = encodeURIComponent(my_string);

и

my_string = decodeURIComponent(cookie_value);

Это, кажется, работает для всех видов персонажей. В противном случае у меня были странные проблемы, даже с символами, которые не были точками с запятой или запятыми.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.