Cookie中允许的字符

时间:2009-12-28 12:21:46

标签: cookies

这个是快速的:

Cookie名称和值中允许的字符是什么?它们与URL或某些常见子集相同吗?

我问的原因是我最近发现了一些奇怪的行为,其名称中包含-的Cookie,我只是想知道它是否是浏览器特定的或者我的代码是否有问题。

13 个答案:

答案 0 :(得分:359)

  

这个是快速的:

你可能认为它应该是,但实际上它根本不存在!

  

Cookie名称和值中允许的字符是什么?

根据古代Netscape cookie_spec,整个NAME=VALUE字符串是:

  

一系列字符,不包括分号,逗号和空格。

所以-应该有效,而且我在这里的浏览器中似乎没问题;你在哪里遇到麻烦?

通过上述含义:

  • =合法包含,但可能含糊不清。浏览器总是在字符串中的第一个=符号上拆分名称和值,因此在实践中,您可以在VALUE中放置=符号,但不能在NAME中放置。

没有提及,因为Netscape在编写规范时非常糟糕,但似乎一直受到浏览器的支持:

  • NAME或VALUE可能是空字符串

  • 如果字符串中根本没有=符号,浏览器会将其视为具有空字符串名称的Cookie,即Set-Cookie: fooSet-Cookie: =foo相同

  • 当浏览器输出一个空名称的cookie时,它们会省略等号。因此Set-Cookie: =bar会产生Cookie: bar

  • 名称和值中的逗号和空格实际上似乎有效,但等号周围的空格被修剪

  • 不允许控制字符(\x00\x1F\x7F

未提及且浏览器完全不一致的是非ASCII(Unicode)字符:

  • 在Opera和Google Chrome中,它们使用UTF-8编码为Cookie标头;
  • 在IE中,使用了机器的默认代码页(特定于语言环境,从不使用UTF-8);
  • Firefox(以及其他基于Mozilla的浏览器)自己使用每个UTF-16代码点的低字节(因此ISO-8859-1没问题,但其他任何东西都被破坏了);
  • Safari只是拒绝发送任何包含非ASCII字符的cookie。

所以实际上你根本不能在cookie中使用非ASCII字符。如果你想使用Unicode,控制代码或其他任意字节序列,cookie_spec要求你使用你自己选择的ad-hoc编码方案,并建议URL编码(由JavaScript的encodeURIComponent生成)作为一个合理的选择

实际标准而言,已经有一些尝试编纂cookie行为,但到目前为止还没有人真正反映现实世界。

  • RFC 2109试图编纂和修复原始的Netscape cookie_spec。在此标准中,不允许使用更多特殊字符,因为它使用RFC 2616令牌(- 仍然允许在那里),并且只有值可以在引用中指定 - 字符串与其他字符。没有浏览器实现过限制,引用字符串和转义的特殊处理,或本规范中的新功能。

  • RFC 2965是另一回事,整理2109并在'版本2 cookies'方案下添加更多功能。也没有人实施任何一项。此规范与早期版本具有相同的令牌和引用字符串限制,并且同样是一堆废话。

  • RFC 6265是一个HTML5时代的尝试,以清理历史混乱。它仍然与现实完全不符,但它比早期的尝试要好得多 - 它至少是浏览器支持的适当子集,不会引入任何应该工作但不能工作的语法(就像之前的引用字符串一样)

在6265中,cookie名称仍被指定为RFC 2616 token,这意味着您可以从alphanums中选择加号:

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

在cookie值中,它正式禁止(由浏览器过滤)控制字符和(不一致地实现的)非ASCII字符。它保留了cookie_spec对空格,逗号和分号的禁止,以及与实际实现早期RFC的任何可怜的白痴的兼容,它还禁止反斜杠和引号,除了包含整个值的引号(但在这种情况下,引号仍然被认为是值,而不是编码方案)。因此,您可以使用alphanums plus:

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

在现实世界中,我们仍在使用原始和最差的Netscape cookie_spec,因此使用cookie的代码应该准备好遇到几乎任何东西,但是对于生成cookie的代码,建议坚持使用RFC中的子集6265。

答案 1 :(得分:28)

在ASP.Net中,您可以使用System.Web.HttpUtility在写入cookie之前安全地对cookie值进行编码,并在读取时将其转换回原始格式。

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

这会阻止符号和等号将符号分成一堆名称/值对,因为它被写入cookie。

答案 2 :(得分:17)

我认为这通常是浏览器特定的。为了安全起见,base64编码一个JSON对象,并将所有内容存储在其中。这样你只需解码它并解析JSON。如果不是所有浏览器,base64中使用的所有字符都可以正常使用。

答案 3 :(得分:9)

在这里,尽可能少的单词。专注于不需要转义的角色:

  

对于cookies:

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

对于网址

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

对于cookies和网址(交集)

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

你是怎么回答的。

  

请注意,对于Cookie, = 已被删除,因为它已被删除   通常用于设置cookie值。

对于网址,保留了=。交叉点显然没有。

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

结果发现转义仍然发生且意外发生,尤其是在Java cookie环境中,如果遇到最后一个字符,则cookie用双引号括起来。

为了安全起见,只需使用A-Za-z1-9即可。这就是我要做的事情。

答案 4 :(得分:8)

2011年4月发布的更新rfc6265

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 回答,您会看到更严格的新限制。

答案 5 :(得分:5)

你不能把“;”在cookie的value字段中,将设置的名称是“;”之前的字符串在大多数浏览器中...

答案 6 :(得分:1)

有两种版本的cookies规格
 1.版本0 cookie又名Netscape cookie,
 2.版本1又名RFC 2965 cookie
在版本0中,cookie的名称和值部分是字符序列,不包括分号,逗号,等号和空格,如果不与双引号一起使用
 版本1更复杂,你可以检查它here
在此版本中,名称值部分的规格几乎相同,但名称不能以$ sign开头

答案 7 :(得分:1)

IE和Edge还有另一个有趣的问题。名称超过1个周期的Cookie似乎会被默默地删除。 所以 这有效:

  

cookie_name_a =值a

虽然这会被取消

  

cookie.name.a =值a

答案 8 :(得分:0)

很简单:

  

可以是除控制外的任何US-ASCII字符   字符(CTL),空格或制表符。它还不能包含   分隔符如下所示:()<> @,; :\“ / []?=   {}。

     

可以选择用双引号和任何   US-ASCII字符,不包括CTL,空格,双引号,逗号,   允许使用分号和反斜杠。编码:许多实现   对Cookie值执行URL编码,但是不需要   RFC规范。它确实有助于满足有关以下方面的要求   但是允许使用哪些字符。

链接:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Directives

答案 9 :(得分: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中进行一些设置,以允许将cookie中使用的base64字符串不损坏地传输回PHP。同时,这有效。 “ +”可能是“合法”的cookie值,但是如果您希望将这样的字符串传输回PHP(以我为例,通过$ _COOKIE数组),我建议重新处理以删除冒犯性格,并在恢复后将其还原。还有许多其他的“ cookie安全”字符可供选择。

答案 10 :(得分:0)

如果以后使用这些变量,您会发现path之类的东西实际上会让带重音符号的字符通过,但实际上与浏览器路径不匹配。为此,您需要对它们进行URIEncode。所以就是这样:

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

因此,“允许的”字符可能会超出规范中的字符。但是您应该遵守规范,并使用URI编码的字符串来保证安全。

答案 11 :(得分:-1)

多年前MSIE 5或5.5(可能两者)在HTML块中出现了一些严重的“ - ”问题,如果你能相信的话。虽然它没有直接相关,因为我们已经在cookie中存储了MD5哈希(仅包含字母和数字)以查找服务器端数据库中的所有其他内容。

答案 12 :(得分:-2)

我最终使用

view model

view model

这似乎适用于各种字符。否则我就遇到了奇怪的问题,即使使用的字符不是分号或逗号。