8

无论后端平台如何,我都很难弄清楚编码/解码 cookie 值的标准是什么(或者有什么标准?)。

根据RFC 2109

VALUE 对用户代理是不透明的,可以是源服务器选择发送的任何内容,可能是服务器选择的可打印 ASCII 编码。“不透明”意味着内容仅对原始服务器感兴趣和相关。事实上,任何检查 Set-Cookie 标头的人都可以读取该内容。

这听起来像“服务器是老板”,它决定了编码将适用什么。这使得从 PHP 后端设置 cookie 并从 Python 或 Java 或其他任何方式读取它变得非常困难,而无需在双方都编写任何手动编码/解码处理。

假设我们有一个需要编码的值。俄语/"печенье (*} значения"/的意思是“cookie 值”,其中包含一些额外的非字母数字字符。

Python:

几乎每个 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\"/"

节点.js:

根本没有测试过,但我只是猜测 JavaScript 后端会使用使用十六进制转义/取消转义的本机encodeURIComponentdecodeURIComponent函数来做到这一点?

PHP:

PHP 将urlencode应用于类似于encodeURIComponent但不完全相同的 cookie 值。

所以原始值变成了;%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这甚至没有用双引号括起来。

然而; 如果 JavaScriptvalue变量具有上面的 PHP 编码值,decodeURIComponent(value)则给出/"печенье+(*}+значения"/,请参阅“+”字符而不是空格。

Java、Ruby、Perl 和 .NET 的情况如何?哪种语言遵循(或最接近)期望的行为。实际上,W3对此是否有任何标准?

4

3 回答 3

4

我认为您在这里有些混乱。服务器的编码对客户端无关紧要,也不应该如此。这就是 RFC 2109 在这里想要表达的。

http 中 cookie 的概念与现实生活中的类似:支付俱乐部的入场费后,您的手腕上会得到一个墨水印章。这使您可以离开并重新进入俱乐部而无需再次付款。您所要做的就是向保镖展示您的手腕。在这个现实生活中的例子中,你并不关心它的样子,它甚至可能在普通光线下是不可见的——重要的是保镖能识别出它。如果您将其洗掉,您将失去重新进入俱乐部而无需再次付款的特权。

在 HTTP 中,同样的事情正在发生。服务器使用浏览器设置 cookie。当浏览器返回服务器时(阅读:下一个 HTTP 请求),它会将 cookie 显示给服务器。服务器识别 cookie,并采取相应的行动。这样的 cookie 可以像“WasHereBefore”标记一样简单。同样,浏览器理解它是什么并不重要。如果你删除你的 cookie,服务器就会表现得好像它以前从未见过你一样,就像那个俱乐部的保镖如果你洗掉了那个墨水印章一样。

今天,许多 cookie 只存储一个重要信息:会话标识符。其他所有内容都存储在服务器端并与该会话标识符相关联。该系统的优点是实际数据永远不会离开服务器,因此可以信任。存储在客户端的所有内容都可能被篡改,不应被信任。

编辑:在阅读您的评论并再次阅读您的问题之后,我想我终于理解了您的情况,以及为什么您对 cookie 的实际编码感兴趣,而不是仅仅将其留给您的编程语言:如果您有两个不同的软件环境相同的服务器(例如:PerlPHP),您可能想要解码由其他语言设置的 cookie。在上面的例子中,PHP 必须解码 Perl cookie,反之亦然。

数据在 cookie 中的存储方式没有标准。该标准只说浏览器将完全按照收到的 cookie 发送回去。使用的编码方案是您的编程语言认为合适的。

回到现实生活中的例子,你现在有两个保镖,一个说英语,另一个说俄语。两者必须就一种类型的墨水印章达成一致。这很可能会涉及其中至少一个人学习另一个人的语言。

由于浏览器行为是标准化的,您可以在服务器上使用的所有其他语言中模仿一种语言编码方案,或者简单地在所有正在使用的语言中创建自己的标准化编码方案。您可能必须使用较低级别的例程,例如 PHP,header()而不是较高级别的例程,例如start_session()才能实现此目的。

顺便说一句:以同样的方式,决定如何存储服务器端会话数据的是服务器端编程语言。您不能CGI::Session使用 PHP 的$_SESSION数组来访问 Perl。

于 2013-03-05T20:11:27.557 回答
2

不管 cookie 对客户端是不透明的,它仍然需要符合 HTTP 规范。rfc2616指定所有 HTTP 标头都应为 ASCII (ISO-8859-1)。rfc5987将其扩展为支持其他字符集,但我不知道它的支持范围有多广。

于 2013-03-06T00:00:45.157 回答
0

我更喜欢编码成 UTF8 并使用 base64 编码进行包装。它快速、无处不在,并且永远不会在任何一端破坏您的数据。

即使在包装时,您也需要确保显式转换为 UTF8。其他语言和运行时,虽然支持 Unicode,但可能不会像许多 Windows API 一样在内部将字符串存储为 UTF8。根据我的经验,Python 2.x 很少在没有显式转换的情况下正确获取 Unicode 字符串。

编码:nativeString -> utfEncode() -> base64Encode()

解码:base64Decode() -> utfDecode() -> nativeString

这些天来,我所知道的几乎所有语言都支持这一点。您可以寻找通用的单功能编码,但我会谨慎行事并选择两步方法......尤其是使用外来字符集。

于 2013-03-06T07:21:32.607 回答