cookie 中允许使用哪些字符?
Posted
技术标签:
【中文标题】cookie 中允许使用哪些字符?【英文标题】:What are allowed characters in cookies? 【发布时间】:2010-12-30 11:11:31 【问题描述】:cookie 名称和值中允许使用哪些字符?它们与 URL 相同还是某些公共子集?
我问的原因是我最近遇到了一些奇怪的行为,cookie 的名称中包含 -
,我只是想知道这是浏览器特定的东西还是我的代码有问题。
【问题讨论】:
相关Is the name of a cookie case sensitive? 【参考方案1】:我认为它通常是特定于浏览器的。为了安全起见,base64 对 JSON 对象进行编码,并将所有内容存储在其中。这样,您只需对其进行解码并解析 JSON。 base64 中使用的所有字符都应该在大多数浏览器(如果不是所有浏览器)上都能正常播放。
【讨论】:
这个答案似乎是跨浏览器的一致答案。在工作了好几个小时试图找到一个快速的解决方案后,我意识到了这一点:我也没有得到一个。只需按照上面的建议进行操作即可省去麻烦。 没试过这个,但我读过其他关于这个的帖子说base64编码只适用于ascii字符。【参考方案2】:有 2 个版本的 cookie 规范 1. 版本 0 cookie 又名 Netscape cookie, 2. 版本 1 又名 RFC 2965 cookie 在版本 0 中,cookie 的名称和值部分是字符序列,不包括分号、逗号、等号和空格,如果不与双引号一起使用 版本 1 要复杂得多,您可以查看它here 在此版本中,名称值部分的规范几乎相同,只是名称不能以 $ 符号开头
【讨论】:
在哪里说值必须排除版本 0 中的等号?【参考方案3】:这个很快:
你可能认为它应该是,但实际上根本不是!
cookie 名称和值中允许使用哪些字符?
根据古代网景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:整个值必须是带引号的字符串,所以它必须是 Name="Va;lue"; max-age...
。它在浏览器中不起作用,并且在 RFC 6265 中是不允许的,它被提议替换 2965 并试图更好地反映现实。
@bobince - 我知道这很旧,但我是否正确阅读了您的答案,是否意味着 cookie 值中在技术上不允许使用空格? "不包括分号、逗号和空格" [强调我的]
@Adam:是的,如果您遵循 Netscape 规范或 RFC 6265,则在原始(未 DQUOTEd)cookie 值中不允许使用空格。它仍然在我尝试过的浏览器中工作,但我不会依赖它。
RFC 6265 将标记定义为1*<any CHAR except CTLs or separators>
,分隔符为(
、)
、<
、>
、@
、,
、;
、;
@,\
,"
,/
,[
,]
,?
,=
,
,
,HT
,所以HT
的cookie名称应该是是字母加!#$%&'*+-.?^_`|~
【参考方案4】:
在 ASP.Net 中,您可以使用 System.Web.HttpUtility
在写入 cookie 之前安全地对 cookie 值进行编码,并在读出时将其转换回其原始形式。
// Encode
HttpUtility.UrlEncode(cookieData);
// Decode
HttpUtility.UrlDecode(encodedCookieData);
这将阻止 & 和等号在将值写入 cookie 时将其拆分为一组名称/值对。
【讨论】:
请注意,asp.net 内部在存储身份验证 cookie 时使用十六进制编码而不是 UrlEncode。 referencesource.microsoft.com#System.Web/Security/… 所以可能在某些情况下 url 编码不会削减它?【参考方案5】:几年前,如果您相信的话,MSIE 5 或 5.5(可能两者都有)在 HTML 块中出现了一些严重的问题,即“-”。虽然它不是直接相关的,但自从我们在 cookie 中存储了一个 MD5 哈希(仅包含字母和数字)以查找服务器端数据库中的所有其他内容之后。
【讨论】:
【参考方案6】:你不能放“;”在 cookie 的 value 字段中,将设置的名称是字符串,直到 ";"在大多数浏览器中...
【讨论】:
【参考方案7】:较新的rfc6265 于 2011 年 4 月发布:
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.4 节中的文字...该图以; OWS
分隔,文字需要文字;
(带空格)。【参考方案8】:
IE 和 Edge 还有一个有趣的问题。名称超过 1 个句点的 Cookie 似乎会被默默删除。 所以 这有效:
cookie_name_a=值a
虽然这将被删除
cookie.name.a=值a
【讨论】:
如果您添加确切的浏览器版本以便我们复制,那就太好了,因为浏览器的行为在 cookie 上并不一致。 cookie-name-a = valueA 怎么样?【参考方案9】:就是这样,用尽可能少的文字。专注于不需要转义的字符:
对于 cookie:
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!#$%&'()*+-./:<>?@[]^_`|~
对于网址
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789.-_~!$&'()*+,;=:@
对于cookies和url(交集)
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!$&'()*+-.:@_~
这就是你的回答。
请注意,对于 cookie,= 已被删除,因为它是 通常用于设置cookie值。
对于 url,这个 = 被保留。十字路口显然没有。
var chars = "abdefghijklmnqrstuvxyz"; chars += chars.toUpperCase() + "0123456789" + "!$&'()*+-.:@_~";
结果转义仍在发生和意外发生,尤其是在 Java cookie 环境中,如果 cookie 遇到最后一个字符,则用双引号括起来。
为了安全起见,请使用 A-Za-z1-9。这就是我要做的。
【讨论】:
Safari Cookies 是我唯一有问题的浏览器——所有其他浏览器都运行良好。我必须对我的 cookie 进行 UrlEncode 和 UrlDecode 来处理等号 = 符号和空格。就像 Cookie 中的 Base64Encode。 (Safari 只需要这个 - 其他浏览器在有和没有编码 cookie 的情况下都可以正常工作。) 最好列出导致答案的来源! @Loc 超过 3 小时的试用和检查。【参考方案10】:这很简单:
可以是除控制以外的任何 US-ASCII 字符 字符 (CTL)、空格或制表符。它也不得包含 分隔符如下: ( ) @ , ; : \ " / [ ] ? = 。
可以选择用双引号和任何 US-ASCII 字符,不包括 CTL、空格、双引号、逗号、 允许使用分号和反斜杠。编码:许多实现 对 cookie 值执行 URL 编码,但不是必须的 RFC 规范。它确实有助于满足关于 但是允许使用哪些字符。
链接:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Directives
【讨论】:
【参考方案11】:还有一个考虑因素。我最近实施了一个方案,其中发布到 php 脚本的一些敏感数据需要转换并作为加密 cookie 返回,它使用了我认为可以保证“安全”的所有 base64 值。所以我尽职尽责地使用 RC4 加密数据项,运行通过base64_encode输出,并愉快地将cookie返回到站点。测试似乎进展顺利,直到base64编码的字符串包含一个“+”符号。字符串被写入页面cookie没有问题。使用浏览器诊断我也可以验证 cookie 是否未更改。然后当后续页面调用我的 PHP 并通过 $_COOKIE 数组获取 cookie 时,我结结巴巴地发现字符串现在缺少“+”号。该字符的每次出现都被替换为ASCII 空格。
考虑到从那时起我读过多少类似的未解决的投诉来描述这种情况,经常引用大量使用 base64 来“安全地”在 cookie 中存储任意数据的引用,我想我会指出问题并提供我公认的笨拙解决方案。
在您对一段数据进行任何加密后,然后使用 base64_encode 使其“cookie-safe”,通过此运行输出字符串...
// 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 而不会丢失字符。我只需要记住通过我创建的同一个 fix64() 调用将 cookie 传回,然后我可以使用通常的 base64_decode() 对其进行解码,然后在您的方案中进行任何其他解密。
我可以在 PHP 中进行一些设置,允许将 cookie 中使用的 base64 字符串传输回 PHP 而不会损坏。与此同时,这有效。 “+”可能是“合法”的 cookie 值,但如果您希望能够将这样的字符串传输回 PHP(在我的情况下是通过 $_COOKIE 数组),我建议重新处理以删除冒犯的角色,并在恢复后恢复它们。还有许多其他“cookie 安全”字符可供选择。
【讨论】:
【参考方案12】:我最终使用了
cookie_value = encodeURIComponent(my_string);
和
my_string = decodeURIComponent(cookie_value);
这似乎适用于所有类型的角色。否则我会遇到奇怪的问题,即使字符不是分号或逗号。
【讨论】:
【参考方案13】:如果你稍后使用变量,你会发现像path
这样的东西实际上会让重音字符通过,但它实际上与浏览器路径不匹配。为此,您需要对它们进行 URIEncode。所以就像这样:
const encodedPath = encodeURI(myPath);
document.cookie = `use_pwa=true; domain=$location.host; path=$encodedPath;`
所以“允许”的字符可能比规范中的更多。但是您应该遵守规范,并使用 URI 编码的字符串以确保安全。
【讨论】:
以上是关于cookie 中允许使用哪些字符?的主要内容,如果未能解决你的问题,请参考以下文章