Cookie中允许使用哪些字符?


301

Cookie名称和值中允许使用哪些字符?它们是否与URL或某些公共子集相同?

我问的原因是,我最近用-其名称中的cookie遇到了一些奇怪的行为,我只是想知道这是特定于浏览器还是我的代码有问题。

Answers:


391

这是一个快捷方式:

您可能会认为应该如此,但实际上并非如此!

Cookie名称和值中允许使用哪些字符?

根据古老的Netscape cookie_spec,整个NAME=VALUE字符串为:

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

因此-应该可以工作,而且在我来到这里的浏览器中似乎还可以;您在哪里遇到麻烦?

通过以上暗示:

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

没有提到什么,因为Netscape在编写规范时很糟糕,但是似乎始终受到浏览器的支持:

  • NAME或VALUE可能为空字符串

  • 如果=字符串中根本没有符号,则浏览器会将其视为具有空字符串名称的Cookie,即Set-Cookie: foo与相同Set-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要求您使用自己选择的即席编码方案,并建议将URL编码(由JavaScript产生encodeURIComponent)作为合理选择。

实际标准方面,已经进行了一些尝试来整理Cookie行为,但是到目前为止,还没有任何方法能够真正反映出现实世界。

  • RFC 2109试图对原始Netscape cookie_spec进行编码和修复。在该标准中有更多的特殊字符都不允许,因为它使用RFC 2616级的令牌(一个-仍然允许存在),并且只有该值可以在一个引用字符串与其他字符来指定。没有浏览器实现限制,对引号引起的字符串的特殊处理和转义,或者该规范中的新功能。

  • RFC 2965是另一种解决方法,它整理了2109,并在“版本2 cookie”方案下添加了更多功能。也没有人实施过任何一个。该规范与早期版本具有相同的标记和引号字符串限制,并且是一堆废话。

  • RFC 6265是HTML5时代试图清除历史混乱的尝试。它仍然不能完全符合现实,但是比早期的尝试要好得多-它至少是浏览器支持的一个适当子集,没有引入任何应该起作用但不起作用的语法(例如之前的带引号的字符串) 。

在6265中,cookie名称仍指定为RFC 2616 token,这意味着您可以从字母数字加:

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

在cookie值中,它正式禁止(由浏览器过滤)控制字符和(不一致执行的)非ASCII字符。它保留了cookie_spec对空格,逗号和分号的禁止,并且为了与实际上实施较早RFC的任何可怜的白痴兼容,它还禁止反斜杠和引号,但引号包装了整个值(但在这种情况下,引号仍被认为是值,而不是编码方案)。这样就剩下字母数字加号了:

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

在现实世界中,我们仍在使用原始和最差的Netscape cookie_spec,因此应该准备使用cookie的代码来处理几乎所有事情,但是对于生成cookie的代码,建议坚持使用RFC 6265中的子集。


@bobince您是说RFC指出,只要cookie值;被双引号括起来,它就可以具有该字符?因此:Set-Cookie: Name=Va";"lue; Max-Age=3600
Pacerier

@Pacerier:整个值必须为带引号的字符串,因此必须为Name="Va;lue"; max-age...。它在浏览器中不起作用,并且在RFC 6265中是不允许的,建议将其替换为2965,并尝试更好地反映现实。
bobince'7

@bobince-我知道这很旧,但是我是否正确阅读了您的答案以表示Cookie值在技术上不允许使用空格?“不包括分号,逗号和空格 [强调我的内容]
Adam Rackis

1
@Adam:是的,如果要按照Netscape规范或RFC 6265进行操作,则原始(un-DQUOTEd)Cookie值中不允许使用空格。尽管如此,它仍然可以在我尝试过的浏览器中工作,但我不会依赖它。
bobince

2
RFC 6265所定义令牌1*<any CHAR except CTLs or separators>和分离器()<>@,;:\"/[]?={}SPHT,所以cookie名称应该是alphanums加!#$%&'*+-.?^_`|~
甘泉

28

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

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

这将终止与号,并在将值写入Cookie时将等值分割为一堆名称/值对的等号。


1
请注意,存储身份验证Cookie时,内部asp.net使用十六进制编码而不是UrlEncode。referencesource.microsoft.com#System.Web / Security /…因此,在某些情况下url编码不会删除它?
彼得

17

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


这个答案似乎是跨浏览器的一致答案。我花了很多时间试图找到一种快速的解决方案,然后才意识到这一点:我也没有。请按照上述建议进行操作,以免麻烦。
微笑

没有尝试过,但是我读过其他文章,说base64编码仅适用于ascii字符。
user984003

11

这里就是用最少的话。着眼于不需要转义的字符:

饼干:

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

对于网址

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

对于cookie和url(交集)

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

那就是你的回答。

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

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

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

事实证明转义仍然在发生和意外发生,特别是在Java cookie环境中,如果cookie遇到最后一个字符,则用双引号引起来。

为了安全起见,只需使用A-Za-z1-9。那就是我要做的。


Safari Cookies是我唯一的问题浏览器–所有其他浏览器都运行良好。我必须对Cookie进行UrlEncode和UrlDecode处理等号和空格。就像Cookie中的Base64Encode一样。(仅Safari需要此功能,其他浏览器在使用和不使用编码cookie的情况下都可以正常工作。)
Sql Surfer

最好列出列出您答案的来源!
Loc

1
@Loc经过3个小时的试用和检查。
mmm

10

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答案,则会发现更新的限制更加严格。


6

您不能输入“;” 在Cookie的value字段中,要设置的名称是字符串,直到“;”为止 在大多数浏览器中...


1

Cookie规范有2个版本
。1.版本0(又名Netscape cookie),
版本2(又名RFC 2965)cookie
在版本0中,cookie的名称和值部分是字符序列,不包括分号,逗号,等号和空格。 ,如果不使用双引号
版本1则要复杂得多,您可以在此处进行检查
在此版本中,名称值部分几乎相同,只是名称不能以$符号开头


它在哪里说值必须在版本0中排除等号?
吉利2014年

1

IE和Edge还有另一个有趣的问题。名称超过1个句点的Cookie似乎已被静默删除。所以这工作:

cookie_name_a = valuea

虽然这将被丢弃

cookie.name.a = valuea


如果您添加了确切的浏览器版本以便我们复制,那会很好,因为浏览器的行为在Cookie上不一致。
杰拉尔德

0

很简单:

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

可以选择将<cookie-value>设置为双引号,并且允许使用任何US-ASCII字符(CTL,空格,双引号,逗号,分号和反斜杠除外)。编码:许多实现都对Cookie值执行URL编码,但是RFC规范不是必需的。它确实有助于满足有关允许使用哪些字符的要求。

链接:https//developer.mozilla.org/zh-CN/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中进行一些设置,以允许将cookie中使用的base64字符串不损坏地传输回PHP。同时,这可行。“ +”可能是“合法”的cookie值,但是如果您希望能够将这样的字符串传输回PHP(以我为例,通过$ _COOKIE数组),我建议重新处理以删除冒犯性格,并在恢复后将其还原。还有许多其他的“ 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块中的“-”都有一些严重的问题。尽管它并不直接相关,但是因为我们已经在cookie中存储了MD5哈希(仅包含字母和数字)以查找服务器端数据库中的所有其他内容。


-2

我最终使用

cookie_value = encodeURIComponent(my_string);

my_string = decodeURIComponent(cookie_value);

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.