Answers:
这是一个快捷方式:
您可能会认为应该如此,但实际上并非如此!
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)字符:
因此在实践中,您根本不能在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中的子集。
Name="Va;lue"; max-age...
。它在浏览器中不起作用,并且在RFC 6265中是不允许的,建议将其替换为2965,并尝试更好地反映现实。
在ASP.Net中,您可以System.Web.HttpUtility
在写入cookie之前安全地对cookie值进行编码,并在读出后将其转换回其原始形式。
// Encode
HttpUtility.UrlEncode(cookieData);
// Decode
HttpUtility.UrlDecode(encodedCookieData);
这将终止与号,并在将值写入Cookie时将等值分割为一堆名称/值对的等号。
我认为这通常是特定于浏览器的。为了安全起见,base64对JSON对象进行编码,然后将所有内容存储在其中。这样,您只需要解码它并解析JSON。如果不是所有浏览器,base64中使用的所有字符都应该可以正常运行。
这里就是用最少的话。着眼于不需要转义的字符:
饼干:
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!#$%&'()*+-./:<>?@[]^_`{|}~
对于网址
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789.-_~!$&'()*+,;=:@
对于cookie和url(交集)
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!$&'()*+-.:@_~
那就是你的回答。
请注意,对于cookie,=已被删除,因为它通常用于设置cookie值。
对于网址,此=保留。交叉点显然没有。
var chars = "abdefghijklmnqrstuvxyz"; chars += chars.toUpperCase() + "0123456789" + "!$&'()*+-.:@_~";
事实证明转义仍然在发生和意外发生,特别是在Java cookie环境中,如果cookie遇到最后一个字符,则用双引号引起来。
为了安全起见,只需使用A-Za-z1-9。那就是我要做的。
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答案,则会发现更新的限制更加严格。
很简单:
<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
还有一个考虑。我最近实施了一个方案,其中一些敏感数据发布到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安全”字符可供选择。
;
被双引号括起来,它就可以具有该字符?因此:Set-Cookie: Name=Va";"lue; Max-Age=3600