You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
== Server -> User Agent ==
Set-Cookie: lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT
== User Agent -> Server ==
Cookie: SID=31d4d96e407aad42; lang=en-US
user agent将会拒绝cookie,除非Domain属性为cookie指定的作用域会包含源服务器。例如,user agent将会接受一段来自“foo.example.com”的Domain属性为"example.com"或者"foo.example.com"的cookie,但是user agent不会接受Domain属性为"bas.example.com"或者"baz.foo.example.com"的cookie。
user agent的每个cookie会存储下列所述的字段:name,value,expiry-time,domain,
path,creation-time,last-access-time,persistent-flag,host-only-flag,
secure-only-flag,以及http-only-flag。
RFC 6265 要点翻译
1.简介
本文档定义了HTTP Cookie以及HTTP头的Set-Cookie字段。通过使用Set-Cookie头,一个HTTP服务器可以传递name/value键值对以及相对应的元数据(所谓的cookies)到user agent。当user agent向服务器发送后续请求时,user agent会根据元数据和其他信息来决定是否要在Cookie头中返回name/value键值对。
虽然表面上看起来很简单, 但时cookies有很多复杂的地方。例如,服务器在向user agent发送cookie时,对每个cookie会设定一个作用域。 作用域制定了user agent回传cookie的规则:cookie需要回传的最大期限,需要回传cookie到哪些服务器,以及需要应用到哪些模式的URI上。
由于历史原因,cookie包含许多在安全性和隐私上不恰当的地方。例如,服务器可以指定一个给出的cookie字段需要“安全的”连接,但是安全属性并没有保证在存在网络中间人攻击时cookie的完整性。相似的是,给定host的cookies将会被这个host上的所有端口共享,尽管通常来说,浏览器所用的“同源策略”会将从不同端口上取回的东西孤立开来。
这份标准有两类受众:会生产cookie的web服务器的开发者,以及会消费cookie的user agent的开发者。
为了最大化在user agent中的通用性,web服务器在生成cookie时应该把他们自身限制为一个在第4章定义的良好的实现者。
User agent必须实现比第5章中定义的更加宽松的规则,以达到最大化和现有的不符合第4章定义的良好实现者的服务器的互通性。
这份文档说明了在互联网上经常被使用的头的句法和语义。特别地,这份文档并没有创造新的句法和语义。对cookie生成的推荐标准在第4章提供,表述了一些现有服务器行为的子集,在第5章中表述了一些今天并不被推荐的句法和语义,更加宽松的cookie处理算法。某些现存软件的实现和推荐的协议有一些重大的不同,这份文档也包含了一份解释这些不同的内容。
在这份文档之前,至少存在着三份不同的cookie描述:所谓的“Netscape cookie 标准”,RFC 2109, RFC2965。然而,这些文档都没有描述Cookie和Set-Cookie头是如何在互联网上被使用的。根据之前IETF的HTTP状态管理机制的标准,这份文档请求下列操作:
[]将RFC2109的状态改为Historic(已经被RFC2965废止)
[]将RFC2965的状态改为Historic
[]指定RFC2965已经被这份文档废止
特别的是,通过将RFC2965移到Historic并且将其废止,这份文档反对使用Cookie2和Set-Cookie2头。
2.约定
2.1. 一致标准
此处略去几百字
2.2. 句法注解
本文档使用扩充巴科斯范式(ABNF),在RFC5234中有注释。
下列在RFC5234中定义的核心规则被引用,ALPHA(字母),CR(回车),CRLF(CR LF),CTLs(控制字符),DIGIT(数字0-9),DQUOTE(双引号),HEXDIG(十六进制元素 0-9/A-F/a-f),LF(换行符),NUL(空八比特),OCTET(除了NUL以外的所有八比特串),SP(空格),HTAB(水平制表符),CHAR(任意ascii码字符),VCHAR(任意可见的ascii码字符),以及WSP(空白符)。
OWS(可选空白符)规则被用在0个或更多的线性空白符可能出现的场合:
OWS = *([obs-fold]WSP)
obs-fold = CRLF
OWS应该要么不产生要么就产生为一个单独的SP字符。
2.3. 术语
下列术语:user agent,client,server,proxy,origin server(源服务器)和HTTP/1.1标准(RFC2616,1.3节)中的含义相同。
术语request-host是指host的名字,也就是已经被user agent所知的,对user agent来说发送HTTP请求的目的地,或者接收HTTP响应的来源。(也就是发送相应的HTTP请求的host名字)。
术语request-uri已经在RFC2616的5.1.2节中定义。
两个八比特的序列被称为大小写不敏感地相同,当且仅当他们在RFC4790中定义的大小写映射关系被满足时成立。
术语字符串意思是一个非NUL的八位bit序列。
3.概述
这一节概括了一种源服务器将状态信息传递给user agent的方式,也包含了一种user agent将状态信息回传服务器的方式。
为了存储状态,源服务器在HTTP响应中包含了一个Set-Cookie头。在后续的请求中,user agent将回传一个Cookie请求头到源服务器。Cookie头包含了user agent在前面Set-Cookie头中包含的cookie。源服务器可以选择忽略Cookie头或将Cookie用于应用所定义的目的。
源服务器可以在任何响应中发送Set-Cookie响应头。user agent可以在响应码为1xx的请求中忽略Set-Cookie,但必须在除此以外的任何种类响应中处理Set-Cookie(包括响应码为4xx和5xx的响应)。源服务器可以在单个请求的响应中包含多个Set-Cookie字段。Cookie或者Set-Cookie的出现不会阻止存储和复用HTTP请求的缓存。
源服务器不应该把多个Set-Cookie字段打包到单个HTTP头中。通常打包HTTP头的字段可能会更改Set-Cookie字段的语义,因为%x2c(",")字符被Set-Cookie使用,从而在这种打包方式中存在冲突。
3.1. 示例
使用Set-Cookie头,服务器可以向在一个HTTP响应中user agent发送一条短字符串,这条字符串会在未来符合cookie作用域的HTTP请求中回传给服务器。例如,服务器可以给user agent发送一个名叫“SID”的“session标识符”,值为 31d4d96e407aad42。user agent会在后续的请求中回传这个session标识符以及其值。
服务器可以使用Path和Domain属性变更cookie的作用域。例如,服务器可以委托user agent在每个path每个example.com的子域都返回cookie。
就如下一个例子中展示的那样,服务器可以在user agent中存储多个cookie。例如,服务器可以通过返回两个Set-Cookie字段,实现既存储一个session标识符,又存储用户的偏好语言。值得注意的是,服务器用Secure和HttpOnly属性来对更加敏感的session标识符提供额外的安全保护(见4.1.2.)
注意上面的Cookie头包含了两个cookie,一个名叫SID,另一个为lang。如果服务器希望cookie在user agent的多个“会话“(sessions,例如,user agent重启之后)中持续存在,服务器可以在Expires属性中指定一个过期时间。注意,如果user agent的cookie存储超过它的定额或者用户手动删除了cookie的话,user agent可能会在过期时间到达之前删除cookie。
最后,为了移除一个cookie,服务器要返回一个把过期时间设置在过去的Set-Cookie字段。服务器只有在Set-Cookie头中Path和Domain属性与创建cookie时相符时,才能成功删除cookie。
4. 服务端的要求
本节描述了“表现良好”的Cookie和Set-Cookie头的句法和语义。
4.1. Set-Cookie
4.1.1 句法
不正式地说,Set-Cookie响应头包含了名字叫做“Set-Cookie”并跟着的一个“:”以及一个cookie。每个cookie由一个name-value键值对打头,后面跟着0个或者多个attribute-value键值对。服务器不应该发送未能遵从下列语法的Set-Cookie头。
注意上面的参考文档中某些条目使用了一些和这份文档(ABNF,RFC5234)不同的语法标记。
这份文档没有定义任何关于cookie-value的语义。
为了最大化和user agent的兼容性,服务器在要使用一些任意的数据作为cookie-value时,应该将数据编码,例如使用Base64(RFC4648)。
set-cookie-string中由cookie-av项贡献的部分是被大家熟知的属性。为了最大化和user agent的兼容性,服务器不应该产生在set-cookie-string中有两个属性相同的名字的cookie。(关于user agent如何处理这种情况,见5.3节)
服务器不应该在同一个响应中包含超过一个具有相同cookie-name的Set-Cookie字段。(关于如何处理这种情况,见5.2节)
如果一个服务器向user agent并发地发送了多条包含Set-Cookie头的响应(例如,当在多个sockets上和user agent通信时),这些响应将会创造一个“竞争条件”,最终会导致不可预期的后果。
注意:一些现有的user agent对两位数的年份有不同的处理。为了避免兼容性问题,服务器应该使用要求四位数年份的RFC1123定义的日期格式。
注意:一些user agent会用32位的UNIX time_t来存储和处理日期。time_t相关的库的bug可能会导致这些user agent在2038年之后错误地处理日期。
4.1.2. 句法(非正式)
本节描述了简化的关于Set-Cookie头的语义。这些语义对于要理解最常见的服务器上cookie用法已经足够详细。全部地语义在第5节描述。
当user agent接收到一个Set-Cookie头时,user agent会将cookie及其属性一起存储。随后,当user agent发起HTTP请求时,user agent会在Cookie头中包含合适的并且没有过期的cookie。
如果user agent接收到了一个和某个现有cookie的cookie-name、domain-value和path-value都相同的新cookie,现有的那个cookie将会被驱逐,取而代之的是那个新cookie。注意服务器可以通过向user agent发送一个拥有值为过去某一时刻的Expires属性的新cookie,来删除一个cookie。
除非cookie的属性额外指定,cookie将只会回传到源服务器(例如,不会回传到任何子域上),并且cookie将会在当前会话结束时过期(会话由user agent自己定义)。user agent会忽略未被识别的cookie属性(但不会忽略整个cookie)。
4.1.2.1. Expires属性
Expires属性指明了cookie的最大生命周期,形式为cookie过期的时刻。user agent并不被要求在设定的时间之前保留cookie。实际上,user agent经常由于存储压力或者隐私上的考虑驱逐了cookie。
4.1.2.2. Max-Age属性
Max-Age属性指明了cookie的最大生命周期,形式为cookie过期之前的具体秒数。user agent并不被要求在这段指定的时长内保留cookie。实际上,user agent经常由于存储压力或者隐私上的考虑驱逐了cookie。
如果cookie既有Max-Age也有Expires属性,Max-Age属性将会有更高的优先级,并且控制cookie的过期时间。如果一个cookie既没有Max-Age也没有Expires属性,user agent将会在本次会话(会话由user agent定义)结束之前保留这个cookie。
4.1.2.3. Domain属性
Domain属性指明了cookie会被发送到哪些host。例如,如果某cookie的Domain属性的值为"example.com",user agent将会在向example.com,www.example.com以及www.corp.example.com(注意,最前面的%x2E("."), 如果出现,将会被忽略,尽管它除了出现在末尾以外都是非法的)发送HTTP请求时,在Cookie头中包含该cookie。如果服务器漏掉了这个Domain属性,user agent只会向源服务器返回cookie。
user agent将会拒绝cookie,除非Domain属性为cookie指定的作用域会包含源服务器。例如,user agent将会接受一段来自“foo.example.com”的Domain属性为"example.com"或者"foo.example.com"的cookie,但是user agent不会接受Domain属性为"bas.example.com"或者"baz.foo.example.com"的cookie。
注意:出于安全的原因,许多user agent被设定为拒绝Domain属性对应为"公共结尾"的cookie。例如,一些user agent将会拒绝Domain属性为"com"或"co.uk"等。(详见5.3节)
4.1.2.4. Path属性
每个cookie的作用域被限定到了由path组成集合中,由Path属性控制。如果服务器没有提供Path属性,user agent将会使用当前的require-uri中path元素的“目录”作为默认值(更多细节详见5.1.4节)
user agent会在一次HTTP请求中包含该cookie,条件是require-uri中路径的部分匹配Path属性(或者是Path的子目录),其中%x2F("/")被解释为路径分隔符。
虽然这看起来对分隔同一host中不同路径的cookie十分实用,但是Path属性不能作安全的凭据。(见第8节)
4.1.2.5.Secure属性
Secure属性将cookie的作用域限定到“安全的”传输途径(“安全的”是有user agent所定义的)。当一个cookie拥有Secure属性时,user agent只有在请求是从一个安全的传输途径(典型的是以TLS方式传输HTTP,也就是HTTPS,RFC2818)传输时,才会发送该cookie。
尽管这看起来对保护cookie以免受中间人攻击很有用,但是Secure属性只在机密性上保护了cookie。一个网络中间攻击者可以通过非安全的传输途径覆盖该cookie,从而破坏其完整性。(详见8.6节)
4.1.2.6. HttpOnly属性
HttpOnly属性将cookie的作用域限制到HTTP请求中。尤其是,这个属性委托user agent在提供非HTTP方式访问cookie时(例如,浏览器提供给脚本访问cookie的接口),忽略该cookie。
4.2. Cookie
4.2.1. 句法
user agent会将存储的cookie放在Cookie头中发送给源服务器。如果服务器遵从4.1中的要求(并且user agent遵从第5节的要求),user agent将会发送符合下述语法的Cookie头部:
4.2.2. 语义
每个cookie键值对都表述了一个被user agent保存的cookie。cookie键值对包括从Set-Cookie头中接收到的的cookie-name和cookie-value。
注意cookie的属性没有被返回。尤其是,服务器不能单靠Cookie头部就能确定,什么时候cookie会过期,cookie对哪些host有效,对什么路径有效,还有cookie是否设置了Secure或者HttpOnly属性。
每个单独的cookie的语义没有在该文档中定义。服务器被期望以应用相关地语义来填充cookie。
虽然cookie在Cookie头中被线性地序列化,但是服务器不应该依赖序列化的顺序。尤其是,当Cookie头中包含了两个具有相同名字的cookie时(例如,被设置成不同Path或者Domain属性但拥有相同名字的cookie),服务器不应该依赖这些cookie在头部中出现的顺序。
5. User Agent的要求
本节用具体地细节说明了Cookie和Set-Cookie头部,使得实现这些要求的user agent可以和现存的服务器(即使那些不满足第4节中要求的)进行互操作。
5.1. 子元素算法
5.1.1. 日期
user agent必须使用一个和下述算法等价的算法来实现解析cookie-date。注意下述的各种被定义为算法一部分的boolean-flag(例如,found-time,found-day-of-month, found-month,found-year)最初状态是“没有设定”)。
1.使用下述算法,将cookie-date分割成date-token
2.按照下述顺序出列每个在cookie-date中出现的token:
3.如果year的值大于70且小于等于99,在year的值的基础上增加1900.
4.如果year的值大于0且小于等于69,在year值得基础上增加2000.
5.在下列情况中,终止这些步骤并且解析cookie-date以失败告终:
[*] 至少在found-day-of-month,found-month,found-year,或者found-time的flag中有一个没有设定
[*] day-of-month的值小于1或者大于31
[*] year的值小于1601
[*] hour的值大于23
[*] minute的值大于59
[*] second的值大于59
(注意在这个句法中闰秒不能被体现)
6.将解析出的cookie-date转换为UTC时间。如果这个日期不存在,终止算法并且以失败告终。
7.将转换出的时间作为算法的结果返回。
5.1.1. 规范化host名
一个规范的host名是通过下述算法生成的字符串:
5.1.3. Domain匹配
只有在满足下列条件之一时:
给定的字符串才匹配给定的domain字符串的domain。
5.1.4. 路径和路径匹配
user agent必须使用和下述算法等价的算法来计算cookie的默认路径:
至少满足下面的一个条件时,request-path才匹配cookie-path的路径:
5.2. Set-Cookie头
当user agent在一次HTTP响应中接收到一个Set-Cookie字段时,user agent可能会完全会略Set-Cookie字段。例如,user agent可能希望禁止“第三方”cookie(见7.3节)。
如果user agent没有完全忽略Set-Cookie字段,那么user agent必须解析将Set-Cookie头中每个字段的值作为cookie-string解析。(下面将定义)
user agent必须使用和下面所述的算法等价的算法来解析set-cookie-string:
user agent必须使用和下面所述的算法等价的算法来解析unparsed-attributes:
当user agent完成对set-cookie-string的解析时,就说user agent从require-uri中获取到了
名字为cookie-name,值为cookie-value,以及属性为cookie-attribute-list的cookie。(由接收到cookie所触发的额外的要求详见5.3节)
5.2.1. Expires属性
如果attribute-name大小写不敏感地匹配了字符串“Expires”,user agent必须按照下列步骤
处理cookie-av。
令expiry-time的值为将attribute-value按cookie-date(见5.1.1节)解析后的值。
如果attribute-value没有成功地解析成一个cookie date,那么忽略这个cookie-av。
如果expiry-time晚于user agent可以表达的最晚的时间,user agent可以将expiry-time
替换为user agent可以表达的最晚的时间。
如果expiry-time早于user agent可以表达的最早的时间,user agent可以将expiry-time
替换为能表达的最早的时间。
向cookie-attribute-list追加一个属性名为Expires,属性值为expiry-time
的属性。
5.2.2. Max-Age属性
如果attribute-name大小写不敏感地匹配了字符串“Max-Age”,user agent必须按照下列步骤
处理cookie-av。
如果attribute-value的第一个字符不是DIGIT(数字)或者“-”,那么忽略cookie-av。
如果attribute-value剩余的字符中包含一个非DIGIT(非数字)字符,那么忽略这个cookie-av。
令delta-seconds为attribute-value转换为整数之后的值。
如果delta-seconds小于或等于0,令expiry-time为最早可以表达的日期和时间。否则,
令expiry-time为当前的日期和时间加上delta-seconds的秒数。
向cookie-attribute-list追加一个属性名为Max-Age,属性值为expiry-time
的属性。
5.2.3. Domain属性
如果attribute-name大小写不敏感地匹配了字符串“Domain”,user agent必须按照下列步骤
处理cookie-av。
如果attribute-value是空值,那么行为是未知的。然而,user agent应该忽略整条cookie-av。
如果attribute-value的第一个字符是%x2E("."),令cookie-domain为除去attribute-value第一个%x2E(".")之后的值;否则,令cookie-domain的值为整个attribute-value。
将cookie-domain转换为小写。
向cookie-attribute-list追加一个属性名为Domain,属性值为cookie-domain
的属性。
5.2.4. Path属性
如果attribute-name大小写不敏感地匹配了字符串“Path”,user agent必须按照下列步骤
处理cookie-av。
如果attribute-value时空值或者attribute-value的第一个字符不是%x2F(“/”),
那么令cookie-path为默认路径;否则,令cookie-path为整个attribute-value。
向cookie-attribute-list追加一个属性名为Path,属性值为cookie-path
的属性。
5.2.5. Secure属性
如果attribute-name大小写不敏感地匹配了字符串“Secure”,user agent必须向cookie-attribute-list追加一个属性名为Secure,属性值为空的属性。
5.2.5. HttpOnly属性
如果attribute-name大小写不敏感地匹配了字符串“HttpOnly”,user agent必须向cookie-attribute-list追加一个属性名为HttpOnly,属性值为空的属性。
5.3. 存储模型
user agent的每个cookie会存储下列所述的字段:name,value,expiry-time,domain,
path,creation-time,last-access-time,persistent-flag,host-only-flag,
secure-only-flag,以及http-only-flag。
当user agent从一个request-uri接受了一个拥有名叫cookie-name,值为cookie-value,
以及属性为cookie-attribute-list的cookie时,user agent必须像下面这样处理cookie:
当cookie的过期时间是在过去时,这个cookie就是“过期的”。
user agent必须从cookie存储中清除掉所有的过期cookie,条件为在任何时刻,cookie
存储中存在一个过期的cookie时。
在任何时刻,user agent都可能会从cookie存储中“移除过量的cookie”,条件为共享
同一个domain字段的cookie的数量超过了预设的边界值(例如50个cookie)。
在任何时刻,user agent都可能会从cookie存储中“移除过量的cookie”,条件为所有cookie的总数量超过了预设的边界值(例如3000个cookie)。
当user agent从cookie存储中移除过量的cookie时,user agent必须按下面的优先级
清除cookie:
如果两个cookie具有相同的移除优先级,那么user agent必须先移除last-access
更早的那个cookie。
当“当前会话结束”(由user agent定义)时,user agent必须从cookie存储中
移除所有persisitent-flag属性为false的cookie。
5.4. Cookie头
user agent将会在HTTP请求的Cookie头中包含存储的cookie。
当user agent产生一个HTTP请求时,user agent禁止产生多余一个的Cookie头字段。
user agent可能会在HTTP中删除Cookie头部。例如,user agent可能希望禁止
发送从第三方请求中获取到的cookie。(见7.1节)
如果user agnet已经把一个Cookie头部字段添加到HTTP头部中,user agent必须把cookie-string(由下面定义)当做这个头部字段的值发送。
user agent必须用一个等价于下面所述的算法来从cookie存储中结合request-uri,来
计算“cookie-string”:
6. 实现上的考虑
6.1. 限制
实际的user agtn实现在他们能存储的cookie的数目和大小上有限制。常见的user agent
应该提供下述的最小容量:
[] 每个cookie至少4096bytes(以cookie的name,value和attribute之和衡量)
[] 每个domain至少50个cookie
[*] 至少总共3000个cookie
服务器应该使用尽可能小和尽可能小的cookie来防止达到这些实现上的限制,以及最小化
网络带宽的需求,因为Cookie头会在每一个请求中都被包含。
如果user agent未能在Cookie头中返回一个或者多个cookie,服务器应该优雅地处理
这种情况,因为user agent随时可能会按照用户的要求移除任何cookie。
6.2. API
Cookie和Set-Cookie头使用一个这么难懂的句法的原因是,许多平台(包括服务器和
user agent)都提供了一个基于字符串的有关cookie的API,这就要求应用层的开发者
自己生成和解析Cookie和Set-Cookie头,这导致许多程序员错误地实现了,最终导致
不兼容问题。
为了替代提供基于字符串的cookie相关API的做法,平台最好提供更加语义化的API。推荐
详细的API设计超过了本文档的范畴,但是显然接收一个抽象的"Date"对象而不是一段序列化的
date string会有清晰的好处。
6.3. IDNA依赖与迁移
IDNA2008(RFC5890)取代了IDNA2003(RFC3490)。然而,在两份说明中存在差异,
因此处理(比如,转换)从一个标准下注册的域名标签到另一个存在差异。IDNA2003存在的
过渡时期会有一定的时常。user agent应该实现IDNA2008(RFC5890)并且可能会实现
UTS46或者RFC5895以加快IDNA的过渡。如果user agent没有实现IDNA2008,那它应该
实现IDNA2003(RFC3490)。
7. 隐私的考虑
cookie因为允许服务器追踪用户饱受批评。例如,很多“web分析”公司使用cookie来识别
用户是否回到了网站或者访问了另一个站点。虽然cookie不是服务器唯一可以用来追踪跨
HTTP请求的手段,但是cookie促进了追踪,因为他们在user agent的会话之间可以一直存在,
并且可以被多个host共享。
7.1. 第三方cookie
特别令人担忧的是所谓的“第三方”cookie。在渲染一个HMTL文档时,user agent经常从其他
服务器请求资源(例如广告网络)。这些第三方服务器可以使用cookie来跟踪用户,尽管用户
没有直接访问他们的服务器。例如,如果一个用户访问了一个带有第三方内容的网站,之后用户
浏览另一个包含这个内容的网站时,第三方可以跨域两个站点追踪用户。
一些user agent限制了第三方cookie的行为。例如,其中一些user agent拒绝在向第三方的请求中
发送Cookie头部。另外一些则是拒绝处理第三方请求的响应中的Set-Cookie头部。user agent在
处理的第三方cookie策略方面有很多不同。本文档允许user agent在很大范围内尝试第三方cookie的策略,来满足用户对隐私和兼容性的需求。然而,本文档并不偏向于任何特别的第三方cookie策略。
禁止第三方cookie的策略,当服务器尝试绕过这个追踪用户的限制来实现他们隐私追踪时,是无效的。
尤其是,两个协作的服务器经常通过动态url而不是cookie添加识别信息,来追踪用户的时候。
7.2. 用户控制
user agent应该提供一种给用户管理存储在cookie存储中cookie的机制。例如,user agent可能
让用户删除一段时间内的所有cookie或者和某个domain相关的所有cookie另外,许多user agent
都包含了一个让用户检查存储在cookie store中的cookie的界面。
user agent应该提供一种可以让用户禁用cookie的机制。当cookie被禁用时,user agent禁止在
发出的HTTP请求中包含Cookie头部,并且user agent处理收到的HTTP响应中的Set-Cookie头部。
一些user agent提供了阻止cookie跨session存储的选项。当这个被配置到的时候,user agent
必须将所有收到的cookie当做persistent-flag设定为false进行对待。一些流行的user agent
通过“匿名浏览模式”来开放这个功能。
某些user agent提供了允许用户自己写入cookie的能力。在大多数常见的场景中,这会产生大量的
对话框。然而,尽管如此,某些看中隐私的用户认为这个功能很有用。
7.3. 过期时间
虽然服务器可以将cookie的过期时间设定到一个遥远的未来,但是绝大多数user agent实际上并不会
将cookie保留几十年。与其选择无厘头的很长的国务时间,服务器应该,基于实际目的来选择一个合适的cookie过期时间,以提高用户的隐私性。例如,一个典型的cookie标识符应该设置成过期时间为
两周比较合理。
8. 安全考虑
8.1. 概述
cookie可能有很多安全陷阱。本节概述了几个比较显著的问题。
尤其是,cookie鼓励开发者依赖Ambient Authority做认证,往往提供了被攻击的弱点,比如说跨站请求伪造(CSRF)。同时,当在cookie中存储session标识符时,开发者往往也留下了session fixation的隐患。
传输层加密,例如使用HTTPS,并不足以防御网络攻击者获得或者更改受攻击者的cookie,因为cookie协议本身有很多脆弱性(见下面的“弱机密性”和“弱完整性”)。另外,默认情况下,cookie不能从网络攻击者那儿获得完整性和机密性,甚至在使用HTTPS时。
8.2. 环境授权(Ambient Authority)
使用cookie来认证用户的服务器可能会承受安全上的脆弱性,因为一些user agent允许远程组织从
user agent发送HTTP请求(例如,通过HTTP重定向或者HTML表单)。当处理这些请求时,user agent会附上这些cookie,尽管远程组织不知道cookie的内容,但是也潜在地允许远程组织利用在
没有防备性的服务器的授权。
尽管这个安全担忧有过许多名字(比如,跨站请求伪造,confused deputy),这个问题起源于将cookie作为一种环境授权(Ambient Authority)。cookie鼓励服务器的管理员将名称(用URL的形式)和授权(cookie)中分离。结果是,user agent可能会向攻击者指定的地址进行授权,可能导致服务器和客户端承受由攻击者指定的动作,因为他们曾经被用户授权。
服务器管理员可能会考虑通过将URL作为授权表,将名字(URL)和授权绑在一起,来作为取代使用cookie作为授权的手段。取代将secret存在cookie的是,这个方法将secret存在URL中,要求远程
实体自己提供授权。虽然这个方法不是万能药,审慎的运用这个原则可以获得更好的安全性。
8.3. 明文
除非以安全的途径传输(例如TLS),在Cookie和Set-Cookie字头是以明文传输的。
当传输到user agent时(就算在安全的隧道发送cookie也是),服务器应该加密并签名cookie的内容(使用任何服务器想使用的格式)。然而,加密并签名的cookie内容并没有预防攻击者将cookie从一个user agent转移到另一个,或者之后重放cookie进行攻击。
签名和加密每个cookie的内容之外,要求一个更高安全等级的服务器应该只在一个安全的隧道中
使用Cookie和Set-Cookie头。当使用安全渠道的cookie时,服务器应该设定每个cookie的Secure
属性。如果服务器没有设置Secure属性,由安全隧道提供的保护将会很大程度上的没有意义。
例如,考虑一个webmail服务器,将session标识符存在一个cookie钟,并且通过HTTPS访问。如果
服务器没有在它的cookie上设定安全属性,一个活跃的网络攻击者将可以拦截任何由user agent发出的HTTP请求并且将其请求重定向到向HTTP上的webmail服务器。就算webmail服务器没有监听HTTP连接,user agent也会在该请求中包含cookie。这个活跃的网络攻击者拦截这些cookie,并且向服务器重放攻击,之后获取到用户的邮件内容。如果,取而代之,服务器在cookie中设定了Secure属性,
user agent将会在明文请求中包含这个cookie。
8.4. session标识符
服务器一般在cookie中存储一个nonce(或者session标识符)来代替,直接在cookie中存储session信息(可能会被攻击者获得或者重放)。当服务器收到一个拥有nonce的HTTP请求时,服务器会把nonce当做key查找和cookie相关联的状态信息。
使用session标识符限制了攻击者可以造成的危害,如果攻击者拿到了cookie的内容,因为nonce是唯一一个和服务器交互的有用信息(不像非nonce得cookie内容,其本身就是敏感的)。而且,使用单个nonce避免了攻击者将两个交互中的内容混杂起来,造成服务器不可预期的行为。
使用session标识符也不是完全没有风险。例如,服务器应该避免“session fixation”造成的易受攻击性。固化session攻击以下面三个步骤进行。首先,攻击者将session标识符从他的user agent中
移植到受害者的user agent中。第二,受害者使用这个session和服务器交互,可能会用用户信息填充这个session标识符。第三,攻击者直接使用这个session标识符和服务器交互,可能会获得授权信息或者机密信息。
8.5. 弱机密性
cookie没有提供端口隔离。如果一个cookie在一个端口上是可读的,那么这个cookie对另一个运行在同一个服务器上不同端口的服务来说也是可读的。如果一个cookie在一个端口上是可写的,那么这个cookie对另一个运行在同一个服务器上不同端口的服务来说也是可写的。出于这个原因,服务器不应该
在具有相同host的不同端口上运行相互不信任的服务,并且用cookie来存储安全敏感信息。
cookie没有提供协议带来的隔离性。虽然绝大多数通常都使用http和HTTPS协议,给定host的cookie也可能被其他协议获取到,例如ftp和gopher。虽然缺少协议隔离性,对从非HTTP的API获取cookie的权限是显著的,但是实际上由协议导致的隔离性缺失表现在了他们需要自己处理cookie(例如,考虑通过HTTP取回一个使用gopher协议的URI)。
cookie往往也没有提供基于path的隔离性。虽然网络层的协议并没有将存储在一个path的协议发到另一个,但是某些user agent通过非HTTP的api暴露了这些cookie,例如HTML的document.cookie API。因为其中的某些user agent(例如,浏览器)并没有将从不同path获得的资源隔离起来,从一个path取回的某个资源也可能可以拿到存储到另一个path的cookie。
8.6. 弱完整性
cookie没有为兄弟域名(极其子域名)提供完整性保障。例如,考虑foo.example.com和bar.example.com。foo.example.com服务器可以设置一个Domain属性为"example.com"的cookie(可能覆盖一个现有的由bar.example.com设置的"example.com"的cookie)。并且user agent会在想bar.example.com的HTTP请求中包含这个cookie。在最坏的情况下,bar.example.com将不能把这个cookie和一个自己设定cookie区分开来。foo.example.com服务器可能会利用这个能力来发起对bar.example.com的攻击。
尽管Set-Cookie头支持Path属性,path属性也没有提供任何完整性保证,因为user agent将会接受一个Set-Cookie头部的任意路径。例如,一个对 http://example.com/foo/bar 的HTTP响应,可以设置一个Path属性为"/qux"的cookie。因此,服务器不应该在相同host上的不同path运行两个相互不信任的服务,并且使用cookie来存储安全敏感信息。
某个活动的网络攻击者也可以向发送到 https://example.com/ 的请求中的Cookie头部注入cookie,方法是仿造一个 http://example.com/ 的响应并且注入一个Set-Cookie头。位于example.com的HTTPS服务器将不能分辨gaicooie是否是他自己在HTTPS响应中设置的cookie。一个活跃的网络攻击者可能会通过这个机制来攻击example.com,即使example.com只使用了HTTPS。
服务器可以通过加密和签名他们的cookie来缓和这些攻击。然而,使用密码学并没有完全缓解这个问题,因为一个攻击者可以重放TA从真实的example.com服务器中的sessuib获取到的cookie,以导致不可预期的后果。
最后,一个攻击者可以通过存储大量cookie来强迫user agent删除掉cookie。一旦user agent达到了它的存储限制,user agent会被迫驱除掉某些cookie。服务器不应该依赖user agent对cookie的保留。
8.7. 依赖DNS
cookie依赖DNS系统来提供安全性。如果DNS部分或全部受损,cookie协议可能会无法提供应用所要求的安全属性
9. IANA考虑
永久的消息头部注册(RFC3864)已经被下列登记项目更新。
9.1. Cookie
头部名称: Cookie
应用协议: http
状态: 标准
作者/变化控制者: IETF
标准文档: 本文档(5.4节)
9.2. Set-Cookie
头部名称: Set-Cookie
应用协议: http
状态: 标准
作者/变化控制者: IETF
标准文档: 本文档(5.2节)
9.3. Cookie2
头部名称: Cookie2
应用协议: http
状态: 已淘汰
作者/变化控制者: IETF
标准文档: RFC2965
9.4. Set-Cookie2
头部名称: Set-Cookie2
应用协议: http
状态: 已淘汰
作者/变化控制者: IETF
标准文档: RFC2965
The text was updated successfully, but these errors were encountered: