【问题标题】:Language agnostic cookie encoding / decoding standards与语言无关的 cookie 编码/解码标准
【发布时间】:2013-02-09 22:25:28
【问题描述】:

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

根据RFC 2109:

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

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

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

Python:

几乎每个 WSGI 服务器都这样做,并使用 Python 的 SimpleCookie 类从 octal literals 编码/解码,尽管许多人说在 ECMA-262 严格模式下 octal literals are depreciated。怎么回事?

所以,我们的原始 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 后端会使用使用 hexadecimal 转义/取消转义的原生 encodeURIComponent 和 decodeURIComponent 函数来做到这一点?

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 甚至没有用双引号括起来。

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

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

【问题讨论】:

    标签: cookies encoding language-agnostic decoding web-standards


    【解决方案1】:

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

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

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

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

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

    数据在 cookie 中的存储方式没有标准。该标准仅规定浏览器将发送回 cookie与收到时完全相同。使用的编码方案是您的编程语言认为合适的。

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

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

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

    【讨论】:

    • 为隐形墨水+1!尽管 cookie 可以很好地用于在同一个域上的服务器之间共享结构化数据。
    • 是的,很好的例子。如果它回答了 bold 部分的问题,我很乐意为此提供赏金。无论如何,cookie 应该能够跨平台读取,无论它们携带什么类型的数据.. 悲伤和痛苦。
    • 我想我终于明白了你的问题,并相应地编辑了我的答案。
    • 很好的解释和类比。 +1
    【解决方案2】:

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

    【讨论】:

    • ASCII 是 ISO-8859-1 的子集(下半部分)
    • @flup,你是对的。如果我正确理解 rfc,它实际上需要 ASCII。
    【解决方案3】:

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-28
      • 1970-01-01
      • 2016-02-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多