Независимые от языка стандарты кодирования/декодирования файлов cookie

Мне трудно понять, что является стандартом (или есть ли он?) для кодирования/декодирования значений cookie независимо от серверных платформ.

Согласно RFC 2109:

ЗНАЧЕНИЕ непрозрачно для пользовательского агента и может быть чем угодно, что отправит исходный сервер, возможно, в выбранной сервером печатной кодировке ASCII. «Непрозрачный» означает, что содержимое представляет интерес и имеет отношение только к исходному серверу. На самом деле содержимое может быть доступно для чтения любому, кто просматривает заголовок Set-Cookie.

что звучит как «сервер - босс», и он решает, какая кодировка будет применяться. Это затрудняет установку файла cookie, скажем, из бэкэнда PHP, и чтение его из Python, Java или чего-то еще, без написания какой-либо ручной обработки кодирования/декодирования с обеих сторон.

Допустим, у нас есть значение, которое нужно закодировать. Русское /"печенье (*} значения"/ означает «значение файла cookie» с некоторыми дополнительными небуквенно-цифровыми символами.

Питон:

Почти каждый сервер WSGI делает то же самое и использует класс Python SimpleCookie, который кодирует в/декодирует из восьмеричные литералы, хотя многие говорят, что восьмеричные литералы устаревают в строгом режиме ECMA-262. Втф?

Итак, наше необработанное значение cookie становится "/\"\320\277\320\265\321\207\320\265\320\275\321\214\320\265 (*} \320\267\320\275\320\260\321\207\320\265\320\275\320\270\321\217\"/"

Node.js:

Вообще не тестировал, но я просто предполагаю, что бэкэнд JavaScript сделает это с собственным encodeURIComponent и функции decodeURIComponent, которые используют шестнадцатеричный экранирование/неэкранирование?

PHP:

PHP применяет urlencode к значениям cookie, аналогично encodeURIComponent, но не совсем то же самое.

Таким образом, необработанное значение становится; %2F%22%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D1%8C%D0%B5+%28%2A%7D+%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F%22%2F, который даже не заключен в двойные кавычки.

Однако; если переменная JavaScript value имеет закодированное в PHP значение, указанное выше, decodeURIComponent(value) дает /"печенье+(*}+значения"/, см. символы «+» вместо пробелов..

Какова ситуация с Java, Ruby, Perl и .NET? Какой язык соответствует (или наиболее близок) к желаемому поведению. На самом деле, есть ли какой-либо стандарт для этого, определенный W3?


person kirpit    schedule 24.02.2013    source источник


Ответы (3)


Мне кажется, вы тут немного перепутали. Кодировка сервера не имеет значения для клиента, и не должна. Это то, что пытается сказать здесь RFC 2109.

Концепция файлов cookie в http похожа на реальную жизнь: после оплаты вступительного взноса в клуб вы получаете чернильную печать на своем запястье. Это позволяет вам выходить и снова входить в клуб без повторной оплаты. Все, что вам нужно сделать, это показать свое запястье вышибале. В этом примере из реальной жизни вам все равно, как это выглядит, это может быть даже невидимо при обычном освещении — важно только то, что вышибала узнает эту вещь. Если вы смоете его, вы потеряете привилегию снова войти в клуб, не заплатив снова.

В HTTP происходит то же самое. Сервер устанавливает cookie с браузером. Когда браузер возвращается на сервер (читай: следующий HTTP-запрос), он показывает файл cookie серверу. Сервер распознает файл cookie и действует соответствующим образом. Такой файл cookie может быть таким простым, как маркер «WasHereBefore». Опять же, не важно, что браузер понимает, что это такое. Если вы удалите свой файл cookie, сервер будет вести себя так, как будто никогда вас раньше не видел, точно так же, как вышибала в этом клубе, если вы смоете эту чернильную печать.

Сегодня многие файлы cookie хранят только одну важную часть информации: идентификатор сеанса. Все остальное хранится на стороне сервера и связано с этим идентификатором сеанса. Преимущество этой системы в том, что фактические данные никогда не покидают сервер, и поэтому им можно доверять. Все, что хранится на стороне клиента, может быть изменено, и ему нельзя доверять.

Редактировать: После прочтения вашего комментария и вашего вопроса еще раз я думаю, что наконец понял вашу ситуацию и почему вы заинтересованы в фактической кодировке файла cookie, а не просто оставить его на ваш язык программирования: если у вас есть две разные программные среды на одном сервере (например, Perl и PHP), вы можете захотеть декодировать файл cookie, который был установлен другим языком. В приведенном выше примере PHP должен декодировать файл cookie Perl или наоборот.

Не существует стандарта хранения данных в файлах cookie. Стандарт говорит только о том, что браузер отправит файл cookie обратно точно так, как он был получен. Используемая схема кодирования зависит от вашего языка программирования.

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

Поскольку поведение браузера стандартизировано, вы можете либо имитировать схему кодирования одного языка на всех других языках, используемых на вашем сервере, либо просто создать собственную стандартизированную схему кодирования для всех используемых языков. Возможно, вам придется использовать подпрограммы более низкого уровня, такие как header() в PHP, вместо подпрограмм более высокого уровня, таких как start_session(), чтобы добиться этого.

Кстати: точно так же язык программирования на стороне сервера решает, как хранить данные сеанса на стороне сервера. Вы не можете получить доступ к CGI::Session Perl, используя массив PHP $_SESSION.

person Hazzit    schedule 05.03.2013
comment
+1 за невидимые чернила! Хотя файлы cookie вполне могут использоваться для обмена структурированными данными между серверами в одном и том же домене. - person flup; 06.03.2013
comment
да, хороший пример. я бы хотел вознаградить это, если бы оно ответило на вопрос, выделенный жирным шрифтом. в любом случае, файлы cookie должны иметь возможность читаться на разных платформах, независимо от типа данных, которые они несут ... грустно и больно в заднице. - person kirpit; 06.03.2013
comment
Я думаю, что наконец понял ваш вопрос и соответственно отредактировал свой ответ. - person Hazzit; 06.03.2013
comment
Хорошее объяснение и аналогии. +1 - person Saeed Neamati; 24.08.2013

Несмотря на то, что файл cookie непрозрачен для клиента, он все равно должен соответствовать спецификации HTTP. rfc2616 указывает, что все заголовки HTTP должны быть в формате ASCII (ISO-8859-1). rfc5987 расширяет его для поддержки других наборов символов, но я не знаю, насколько широко он поддерживается.

person ykaganovich    schedule 06.03.2013
comment
ASCII является подмножеством (нижняя половина) ISO-8859-1. - person flup; 06.03.2013
comment
@флуп, ты прав. Если я правильно понимаю rfc, на самом деле он ожидает ASCII. - person ykaganovich; 06.03.2013

Я предпочитаю кодировать в UTF8 и использовать кодировку base64. Это быстро, вездесуще и никогда не исказит ваши данные на любом конце.

Вам нужно будет обеспечить явное преобразование в UTF8 даже при его обертывании. Другие языки и среды выполнения, хотя и поддерживают Unicode, могут не хранить строки как UTF8 внутри... как и многие API Windows. Python 2.x, по моему опыту, редко правильно обрабатывает строки Unicode без явного преобразования.

КОДИРОВАНИЕ: nativeString -> utfEncode() -> base64Encode()

ДЕКОДИРОВАНИЕ: base64Decode() -> utfDecode() -> nativeString

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

person pestilence669    schedule 06.03.2013