【发布时间】:2010-12-30 11:11:31
【问题描述】:
cookie 名称和值中允许使用哪些字符?它们与 URL 相同还是某些公共子集?
我问的原因是我最近遇到了一些奇怪的行为,cookie 的名称中包含 -,我只是想知道这是浏览器特定的东西还是我的代码有问题。
【问题讨论】:
标签: cookies
cookie 名称和值中允许使用哪些字符?它们与 URL 相同还是某些公共子集?
我问的原因是我最近遇到了一些奇怪的行为,cookie 的名称中包含 -,我只是想知道这是浏览器特定的东西还是我的代码有问题。
【问题讨论】:
标签: cookies
我认为它通常是特定于浏览器的。为了安全起见,base64 对 JSON 对象进行编码,并将所有内容存储在其中。这样,您只需对其进行解码并解析 JSON。 base64 中使用的所有字符都应该在大多数浏览器(如果不是所有浏览器)上都能正常播放。
【讨论】:
有 2 个版本的 cookie 规范
1. 版本 0 cookie 又名 Netscape cookie,
2. 版本 1 又名 RFC 2965 cookie
在版本 0 中,cookie 的名称和值部分是字符序列,不包括分号、逗号、等号和空格,如果不与双引号一起使用
版本 1 要复杂得多,您可以查看它here
在此版本中,名称值部分的规范几乎相同,只是名称不能以 $ 符号开头
【讨论】:
这个很快:
你可能认为它应该是,但实际上根本不是!
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) 字符:
所以实际上你根本不能在 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.
【讨论】:
; 字符,只要它被双引号括起来?比如:Set-Cookie: Name=Va";"lue; Max-Age=3600
Name="Va;lue"; max-age...。它在浏览器中不起作用,并且在 RFC 6265 中是不允许的,它被提议替换 2965 并试图更好地反映现实。
1*<any CHAR except CTLs or separators>,分隔符为(、)、<、>、@、,、;、; @,\,",/,[,],?,=,{,},HT,所以HT的cookie名称应该是是字母加!#$%&'*+-.?^_`|~
在 ASP.Net 中,您可以使用 System.Web.HttpUtility 在写入 cookie 之前安全地对 cookie 值进行编码,并在读出时将其转换回其原始形式。
// Encode
HttpUtility.UrlEncode(cookieData);
// Decode
HttpUtility.UrlDecode(encodedCookieData);
这将阻止 & 和等号在将值写入 cookie 时将其拆分为一组名称/值对。
【讨论】:
几年前,如果您相信的话,MSIE 5 或 5.5(可能两者都有)在 HTML 块中出现了一些严重的问题,即“-”。虽然它不是直接相关的,但自从我们在 cookie 中存储了一个 MD5 哈希(仅包含字母和数字)以查找服务器端数据库中的所有其他内容之后。
【讨论】:
你不能放“;”在 cookie 的 value 字段中,将设置的名称是字符串,直到 ";"在大多数浏览器中...
【讨论】:
较新的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 的回答,您会发现新的限制更加严格。
【讨论】:
; OWS 分隔,文字需要文字; (带空格)。
IE 和 Edge 还有一个有趣的问题。名称超过 1 个句点的 Cookie 似乎会被默默删除。 所以 这有效:
cookie_name_a=值a
虽然这将被删除
cookie.name.a=值a
【讨论】:
就是这样,用尽可能少的文字。专注于不需要转义的字符:
对于 cookie:
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!#$%&'()*+-./:<>?@[]^_`{|}~
对于网址
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789.-_~!$&'()*+,;=:@
对于cookies和url(交集)
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!$&'()*+-.:@_~
这就是你的回答。
请注意,对于 cookie,= 已被删除,因为它是 通常用于设置cookie值。
对于 url,这个 = 被保留。十字路口显然没有。
var chars = "abdefghijklmnqrstuvxyz"; chars += chars.toUpperCase() + "0123456789" + "!$&'()*+-.:@_~";
结果转义仍在发生和意外发生,尤其是在 Java cookie 环境中,如果 cookie 遇到最后一个字符,则用双引号括起来。
为了安全起见,请使用 A-Za-z1-9。这就是我要做的。
【讨论】:
这很简单:
可以是除控制以外的任何 US-ASCII 字符 字符 (CTL)、空格或制表符。它也不得包含 分隔符如下: ( ) @ , ; : \ " / [ ] ? = { }。
可以选择用双引号和任何 US-ASCII 字符,不包括 CTL、空格、双引号、逗号、 允许使用分号和反斜杠。编码:许多实现 对 cookie 值执行 URL 编码,但不是必须的 RFC 规范。它确实有助于满足关于 但是允许使用哪些字符。
链接:https://developer.mozilla.org/en-US/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-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 安全”字符可供选择。
【讨论】:
我最终使用了
cookie_value = encodeURIComponent(my_string);
和
my_string = decodeURIComponent(cookie_value);
这似乎适用于所有类型的角色。否则我会遇到奇怪的问题,即使字符不是分号或逗号。
【讨论】:
如果你稍后使用变量,你会发现像path 这样的东西实际上会让重音字符通过,但它实际上与浏览器路径不匹配。为此,您需要对它们进行 URIEncode。所以就像这样:
const encodedPath = encodeURI(myPath);
document.cookie = `use_pwa=true; domain=${location.host}; path=${encodedPath};`
所以“允许”的字符可能比规范中的更多。但是您应该遵守规范,并使用 URI 编码的字符串以确保安全。
【讨论】: