HTTP cookies,通常又称作"cookies",已经存在了很长时间,但是仍旧没有被予以充分的理解。首要的问题是存在了诸多误区,认为cookies是后门程序或病毒,或压根不知道它是如何工作的。第二个问题是对于cookies缺少一个一致性的接口。尽管存在着这些问题,cookies仍旧在web开发中起着如此重要的作用,以至于如果cookie在没有可替代品出现的情况下消失,我们许多喜欢的Web应用将变得毫无用处。
cookies的起源
早期Web开发面临的最大问题之一是如何管理状态。简言之,服务器端没有办法知道两个请求是否来自于同一个浏览器。那时的办法是在请求的页面中插入一个token,并且在下一次请求中将这个token返回(至服务器)。这就需要在form中插入一个包含token的隐藏表单域,或着在URL的qurey字符串中传递该token。这两种办法都强调手工操作并且极易出错。
Lou Montulli,那时是网景通讯的一个雇员,被认为在1994年将“magic cookies”的概念应用到了web通讯中。他意图解决的是web中的购物车,现在所有购物网站都依赖购物车。他的最早的说明文档提供了一些cookies工作原理的基本信息该文档在RFC2109中被规范化(这是所有浏览器实现cookies的参考依据),并且最终逐步形成了REF2965.Montulli最终也被授予了关于cookies的美国专利。网景浏览器在它的第一个版本中就开始支持cookies,并且当前所有web浏览器都支持cookies。
cookie是什么?
坦白的说,一个cookie就是存储在用户主机浏览器中的一小段文本文件。Cookies是纯文本形式,它们不包含任何可执行代码。一个Web页面或服务器告之浏览器来将这些信息存储并且基于一系列规则在之后的每个请求中都将该信息返回至服务器。Web服务器之后可以利用这些信息来标识用户。多数需要登录的站点通常会在你的认证信息通过后来设置一个cookie,之后只要这个cookie存在并且合法,你就可以自由的浏览这个站点的所有部分。再次,cookie只是包含了数据,就其本身而言并不有害。
创建cookie
通过HTTP的Set-Cookie消息头,Web服务器可以指定存储一个cookie。Set-Cookie消息的格式如下面的字符串(中括号中的部分都是可选的)
1 | Set-Cookie:value [ ;expires=date][ ;domain=domain][ ;path=path][ ;secure] |
消息头的第一部分,value部分,通常是一个name=value格式的字符串。事实上,原始手册指示这是应该使用的格式,但是浏览器对cookie的所有值并不会按此格式校验。实际上,你可以指定一个不包含等号的字符串并且它同样会被存储。然而,通常性的使用方式是以name=value的格式(并且多数的接口只支持该格式)来指定cookie的值。
当一个cookie存在,并且可选条件允许的话,该cookie的值会在接下来的每个请求中被发送至服务器。cookie的值被存储在名为Cookie的HTTP消息头中,并且只包含了cookie的值,其它的选项全部被去除。例如:
1 | Cookie : value |
通过Set-Cookie指定的选项只是应用于浏览器端,一旦选项被设置后便不会被服务器重新取回。cookie的值与Set-Cookie中指定的值是完全一样的字符串;对于这些值不会有更近一步的解析或转码操作。如果在指定的请求中有多个cookies,那么它们会被分号和空格分开,例如:
1 | Cookie:value1 ; value2 ; name1=value1 |
服务器端框架通常会提供解析cookies的功能,并且通过编程方式获取cookies的值。
cookie编码(cookie encoding)
对于cookie的值进行编码一直都存在一些困惑。通常的观点是cookie的值必须被URL编码,但是这其实是一个谬误,尽管可以对cookie的值进行URL编码。原始的文档中指示仅有三种类型的字符必须进行编码:分号,逗号,和空格。规范中提到可以利用URL编码,但是并不是必须。RFC没有提及任何的编码。然而,几乎所有的实现方式都对cookie的值进行了一些列的URL编码。对于name=value的格式,name和value通常都单独进行编码并且不对等号“=”进行编码操作。
有效期选项(The expires option)
紧跟cookie值后面的每个选项都以分号和空格分割,并且每个选项都指定cookie何时应该被发送到服务器。第一个选项是expires,其指定了cookie何时不会再被发送到服务器端的,因此该cookie可能会被浏览器删掉。该选项所对应的值是一个格式为Wdy,DD-Mon--YYYY HH:MM:SS GMT的值,例如:
1 | Set-Cookie:name=Nicholas;expires=Sat, 02 May 2009 23:38:25 GMT |
在没有expires选项时,cookie的寿命仅限于单一的会话中。浏览器的关闭意味这一次会话的结束,所以会话cookie只存在于浏览器保持打开的状态之下。这就是为什么当你登录到一个web应用时经常看到一个checkbox,询问你是否选择存储你的登录信息:如果你选择是的话,那么一个expires选项会被附加到登录的cookie中。如果expires选项设置了一个过去的时间点,那么这个cookie会被立即删除。
domain选项(The domain option)
下一个选项是domain,指示cookie将要发送到哪个域或那些域中。默认情况下,domain会被设置为创建该cookie的页面所在的域名。例如本站中的cookie的domain属性的默认值为www.nczonline.com。domain选项被用来扩展cookie值所要发送域的数量。例如:
1 | Set-Cookie:name=Nicholas;domain=nczonline.net |
想象诸如Yahoo!这样的大型网站都会有许多以name.yahoo.com(例如:my.yahoo.com,finance.yahoo.com,等等)为格式的站点。单独的一个cookie可以简单的通过将其domain选项设置为yahoo.com而发送到所有这些站点中。浏览器会对domain的值与请求所要发送至的域名,做一个尾部比较(即从字符串的尾部开始比较),并且在匹配后发送一个Cookie消息头。
domain设置的值必须是发送Set-Cookie消息头的域名。例如,我无法向google.com发送一个cookie,因为这个产生安全问题。不合法的domain选项只要简单的忽略即可。
Path选项(The path option)
另一个控制何时发送Cookie消息头的方式是指定path选项。与domain选项相同的是,path指明了在发Cookie消息头之前必须在请求资源中存在一个URL路径。这个比较是通过将path属性值与请求的URL从头开始逐字符串比较完成的。如果字符匹配,则发送Cookie消息头,例如:
1 | Set-Cookie:name=Nicholas;path=/blog |
在这个例子中,path选项值会与/blog,/blogrool等等相匹配;任何以/blog开头的选项都是合法的。要注意的是只有在domain选项核实完毕之后才会对path属性进行比较。path属性的默认值是发送Set-Cookie消息头所对应的URL中的path部分。
secure选项(The secure option)
最后一个选项是secure。不像其它选项,该选项只是一个标记并且没有其它的值。一个secure cookie只有当请求是通过SSL和HTTPS创建时,才会发送到服务器端。这种cookie的内容意指具有很高的价值并且可能潜在的被破解以纯文本形式传输。例如
1 | Set-Cookie:name=Nicholas;secure |
现实中,机密且敏感的信息绝不应该在cookies中存储或传输,因为cookies的整个机制都是原本不安全的。默认情况下,在HTTPS链接上传输的cookies都会被自动添加上secure选项。
cookie的维护和生命周期(cookie maintenance and lifecycle)
任意数量的选项都可以在单一的cookie中指定,并且这些选项可以以任何顺序存在,例如
1 | Set-Cookie:name=Nicholas; domain=nczonline.net; path=/blog |
这个cooke有四个标识符:cookie的name,domain,path,secure标记。要想在将来改变这个cookie的值,需要发送另一个具有相同cookie name,domain,path的Set-Cookie消息头。例如:
1 | Set-Cooke:name=Greg; domain=nczonline.net; path=/blog |
这将以一个新的值来覆盖原来cookie的值。然而,仅仅只是改变这些选项的某一个也会创建一个完全不同的cookie,例如:
1 | Set-Cookie:name=Nicholas; domain=nczonline.net; path=/ |
在返回这个消息头后,会存在两个同时拥有“name”的不同的cookie。如果你访问在www.nczonline.net/blog下的一个页面,以下的消息头将被包含进来:
1 | Cookie:name=Greg;name=Nicholas |
在这个消息头中存在了两个名为“name”的cookie,path值越详细则cookie越靠前。domain-path越详细则cookie字符串越靠前。假设我在ww.nczonline.net/blog下并且发送了另一个cookie,其设置如下:
1 | Set-Cookie:name=Mike |
那么返回的消息头现在则变为:
1 | Cookie:name=Mike;name=Greg;name=Nicholas |
由于包含“Mike”的cookie使用了域名(www.nczonline.net)作为其domain值并且以全路径(/blog)作为其path值,则它较其它两个cookie更加详细。
使用失效日期(using expiration dates)
当cookie创建时包含了失效日期,这个失效日期则关联了以name-domain-path-secure为标识的cookie。要改变一个cookie的失效日期,你必须指定同样的组合。当改变一个cookie的值时,你不必每次都设置失效日期,因为它不是cookie标识信息的组成部分。例如:
1 | Set-Cookie:name=Mike;expires=Sat,03 May 2025 17:44:22 GMT |
现在已经设置了cookie的失效日期,所以下次我想要改变cookie的值时,我只需要使用它的名字:
1 | Set-Cookie:name=Matt |
在cookie上的失效日期并没有改变,因为cookie的标识符是相同的。实际上,只有你手工的改变cookie的失效日期,否则其失效日期不会改变。这意味着在同一个会话中,一个会话cookie可以变成一个持久化cookie(一个可以在多个会话中存在的),反之则不可。为了要将一个持久化cookie变为一个会话cookie,你必须删除这个持久化cookie,这只要设置它的失效日期为过去某个时间之后再创建一个同名的会话cookie就可以实现。
需要记得的是失效日期是以浏览器运行的电脑上的系统时间为基准进行核实的。没有任何办法来来验证这个系统时间是否和服务器的时间同步,所以当服务器时间和浏览器所处系统时间存在差异时这样的设置会出现错误。
cookie自动删除(automatic cookie removal)
cookie会被浏览器自动删除,通常存在以下几种原因:
- 会话cooke(Session cookie)在会话结束时(浏览器关闭)会被删除
- 持久化cookie(Persistent cookie)在到达失效日期时会被删除
- 如果浏览器中的cookie限制到达,那么cookies会被删除以为新建cookies创建空间。详见我的另外一篇关于cookies restrictions的博客
对于任何这些自动删除来说,Cookie管理显得十分重要,因为这些删除都是无意识的。
Cookie限制条件(Cookie restrictions)
在cookies上存在了诸多限制条件,来阻止cookie滥用并保护浏览器和服务器免受一些负面影响。有两种cookies的限制条件:cookies的属性和cookies的总大小。原始的规范中限定每个域名下不超过20个cookies,早期的浏览器都遵循该规范,并且在IE7中有个更近一步的提升。在微软的一次更新中,他们在IE7中增加cookies的限制到50个,与此同时Opera限定cookies个数为30.Safari和Chrome对与每个域名下的cookies个数没有限制。
发向服务器的所有cookies的最大数量(空间)仍旧维持原始规范中所指出的:4KB。所有超出该限制的cookies都会被截掉并且不会发送至服务器。
Subcookies
鉴于cookie的数量限制,开发者提出的subcookies的观点来增加cookies的存储量。Subcookies是一些存储在一个cookie的value中的一些name-value对,并且通常与以下格式类似:
1 | name=a=b&c=d&e=f&g=h |
这种方式允许在单个cookie中保存多个name-value对,而不会超过浏览器cookie的数量限制。通过这种方式创建cookies的负面影响是,需要自定义解析方式来提取这些值,相比较而言cookies的格式会更为简单。服务器端框架已开始支持subcookies的存储。我编写的YUI Cookie utility,支持在javascript中读/写subcookies
Javascript中的cookie(cookie In Javascript)
通过Javascript中的document.cookie属性,你可以创建,维护和删除cookies。当要创建cookies时该属性等同于Set-Cookie消息头,而在读取cookie时则等同于Cookie消息头。在创建一个cookie时,你需要使用和Set-Cookie期望格式相同的字符串:
1 | document.cookie="name=Nicholas;domain=nczonline.net;path=/"; |
设置document.cookie属性的值并不会删除存储在页面中的所有cookies。它只简单的创建或修改字符串中指定的cookies。下次发送一个请求到服务器时,这些cookies(通过document.cookie设置的)会和其它通过Set-Cookie消息头设置的cookies一样发送至服务器。所有这些cookies并没有什么明确的不同之处。
要使用Javascript提取cookie的值时,只要从document.cookie中读取即可。返回的字符串与Cookie消息头中的字符串格式相同,所以多个cookies会被分号和字符串分割。例如:
1 | name1=Greg; name2=Nicholas |
鉴于此,你需要手工解析这个cookie字符串来提取真实的cookie数据。当前已有许多描述利用Javascript来解析cookie的资料,包括我的书,Professional Javascript,所以在这我就不再说明。通常利用已存在的Javascript库操作cookie会更简单,如YUI Cookie utility 来在Javascript中处理cookies而不要手工重新创建这些算法。
通过访问document.cookie返回的cookies遵循发向服务器的cookies一样的访问规则。要通过Javascript访问cookies,该页面和cookies必须在相同的域中,有相同的path,有相同的安全级别。
注意:一旦cookies通过Javascript设置后遍不能提取它的选项,所以你将不会知道domain,path,expiration日期或secure标记。
HTTP-Only cookies
微软的IE6 SP1在cookies中引入了一个新的选项:HTTP-only cookies.HTTP-Only背后的意思是告之浏览器该cookie绝不应该通过Javascript的document.cookie属性访问。设计该特征意在提供一个安全措施来帮助阻止通过Javascript发起的跨站脚本攻击(XSS)窃取cookie的行为(我会在另一篇博客中讨论安全问题,本篇如此已足够)。今天Firefox2.0.0.5+,Opera9.5+,Chrome都支持HTTP-Only cookies。3.2版本的Safari仍不支持。
要创建一个HTTP-Only cookie,只要向你的cookie中添加一个HTTP-Only标记即可:
1 | Set-Cookie: name=Nicholas; HttpOnly |
一旦设定这个标记,通过documen.coookie则不能再访问该cookie。IE同时更近一步并且不允许通过XMLHttpRequest的getAllResponseHeaders()或getResponseHeader()方法访问cookie,然而其它浏览器则允许此行为。Firefox在3.0.6中修复了该漏洞,然而仍旧有许多浏览器漏洞存在,complete browser support list列出了这些。
你不能通过JavaScript设置HTTP-only cookies,因为你不能再通过JavaScript读取这些cookies,这是情理之中的事情。
总结(conclusion)
为了高效的利用cookies,仍旧有许多要了解和弄明白的东西。对于一项创建于十多年前但仍旧如最初实现的那样被使用至今的技术来说,这是件多不可思议的事。本篇只是提供了一些每个人都应该知道的关于浏览器cookies的基本指导,但无论如何,也不是一个完整的参考。对于今天的web来说Cookies仍旧起着非常重要的作用,并且不恰当的管理cookies会导致各种安全性的问题,从最糟糕的用户体验到安全漏洞。我希望这篇手册能够激起一些关于cookies的不可思议的亮点。
写在后面的:
该文章是2009年的,到现在可能已经算一篇比较老的文章,但是文章中关于cookies的讲解十分详细,最近在学习cookies时,读到该文章,觉得值得大家一读,同时也作为自己的参考吧,所以将原文翻译为中文。文中较为详细的讲解了关于cookies的起源,所要解决的问题,以及cookies的本身的属性和每个属性的作用,以及相关浏览器对于cookies的实现情况和延伸情况,正如作者所表达的那样,cookies作为一项十几年前创建却一直沿用至今的技术,值得每个开发者思考并了解和弄明白关于cookies的一些基本信息和原理,译文中尽量保证还原原文本意,但水平有限,一些语句翻译的比较生涩,建议和原文对比阅读,效果可能会比较好一点。
关于作者: Nicholas C. Zakas,资深前端工程师,曾在yahoo工作近五年,并担任前端开发技术领导,他的著作有《javascript 高级程序设计》是一本高质量的前端技术著作。
注:原文链接,转载时请保存原作者链接。
HTTP Cookie 详解二
今天webryan给team做了一个关于HTTP cookie的分享,从各个方面给大家介绍一下大家耳熟能详的Cookie。主要是翻了维基百科的很多内容,因为维基百科的逻辑实在是很清晰:),ppt就不分享了,把原始的草稿贴出来给大家。欢迎批评指正。
HTTP Cookie:
Cookie通常也叫做网站cookie,浏览器cookie或者http cookie,是保存在用户浏览器端的,并在发出http请求时会默认携带的一段文本片段。它可以用来做用户认证,服务器校验等通过文本数据可以处理的问题。
Cookie不是软件,所以它不能被携带病毒,不能执行恶意脚本,不能在用户主机上安装恶意软件。但它们可以被间谍软件用来跟踪用户的浏览行为。所以近年来,已经有是欧洲和美国的一些律师以保护用户隐私之名对cookie的种植宣战了。更严重的是,黑客可以通过偷取Cookie获取受害者的帐号控制权。
1.Cookie的历史
a.概念的产生:
Cookie原名是”magic cookie”,是用来描述程序接受并原样发出的一组数据。(这里可以拿生活中的情况举例:比如说当我们在商场试穿衣服的时候,在试衣间门口店员会给你一个号码牌表示你试穿衣服的件数。当你出来的时候,店员会检查下拿着这个牌子和对应的衣服。)这个概念是一直就存在于计算机领域的.直到1994年,网景公司前雇员Lou Moutulli将magic cookie的概念引入到web,赋予了web记忆。
卖个关子。请大家设想一下,没有cookie的互联网将是一副什么的场景。
1.每次访问都像第一次访问一样,无法判断用户是否访问过
2.任何的购买等交互、验证行为都必须在一次访问中完成
3.无任何记忆,均需要用户重新点击或填写
大家说的很好,在1994年6月的某天,24岁的,网景公司第九位工程师,moutulli,坐在键盘前,遇到和大家描述的一模一样的困难,他凭借着他高超的编程技能和思想设计出了一个五页纸的方案来解决这些棘手的问题,这个五页纸后来也就演变成了最初版本的Netscape Cookie规范。五页纸的核心观点就是在用户的电脑上存放一个小的文件来记录用户对网站的访问情况。moutulli将其简称为cookie. 同年10月,Netscape浏览器就率先支持了Cookies,并在netscape官网上做了检查统计用户是否访问过的功能。次年10月,微软的IE2也开始支持Cookie。当然,微软是要交“保护费”了,因为moutulli在1995年申请了专利,并在1998年获得专利授权。整体来说,Cookie的引入对于互联网来说,这是一个划时代的转折点,它将零散的访问,无状态的请求变得有序并富有记忆,给互联网增添了更有趣味性的玩法。
b.隐私风险
1.1995年Q1,当时Cookie没有受到广泛的关注。但cookie不在用户知晓的情况下可以默认种植引来人们的担心。
2.1996年2月,金融时报(ft中文网就是翻译此杂志)发布关于cookie的文章对公众进行了认知的普及,并引起了媒体的广泛关注和讨论,尤其是在潜在的隐私风险上。
3.1996年-1997年,Cookie在美国联邦贸易委员会听证会持续讨论。
c.规范的发展:
1.1994年,Montulli,联合John Giannandrea写了Netscape cookie规范。
2.1995年4月,在www-talk邮件组第一次开始讨论正式统一的Cookie规范,并在IETF(Internet Engineering Task Force,互联网工程任务组,主要目标是协调制定互联网标准,几乎所有重要的网络底层协议都是有IETF制定,EG:TCP,IP,HTTP and so on,可以毫不夸张的说,没有IETF就没有今天的互联网,今年是IETF成立25周年,老外有很多文章专门回顾总结其光辉成就。IETF是由网民自发组织,自我管理的,任何人都和可以参加的,完全民主平等的,无投票机制的,充分体现了自由、开放、合作、共享的精神)里成立了特别工作小组。两种HTTP Cookie的方案被提议。
3.1996年2月,IETF认定第三方Cookie存在重大隐私风险。
4.1997年2月,IETF最终发布了Cookie规范,RFC 2109,其中指出不允许设置第三方cookie或者不能默认支持第三方cookie
5.2000年10月,RFC 2965发布,主要是由于广告在RFC 2109发布时已经广泛使用第三方Cookie,所以关于第三方cookie部分是没有被Netscape和IE所跟随。
6.2011年4月,RFC 6265发布。现实版使用的Cookie规范终于诞生了。
2.Cookie的类别
a.Session Cookie
这个类型的cookie只在会话期间内有效,即当关闭浏览器的时候,它会被浏览器删除。设置session cookie的办法是:在创建cookie不设置Expires即可。
b.Persistent Cookie
持久型cookie顾名思义就是会长期在用户会话中生效。当你设置cookie的属性Max-Age为1个月的话,那么在这个月里每个相关URL的http请求中都会带有这个cookie。所以它可以记录很多用户初始化或自定义化的信息,比如什么时候第一次登录及弱登录态等。
c.Secure cookie
安全cookie是在https访问下的cookie形态,以确保cookie在从客户端传递到Server的过程中始终加密的。这样做大大的降低的cookie内容直接暴露在黑客面前及被盗取的概率。
d.HttpOnly Cookie
目前主流的浏览器已经都支持了httponly cookie。1.IE5+ 2.Firefox 1.0+ 3.Opera 8.0+ 4.Safari/Chrome。在支持httponly的浏览器上,设置成httponly的cookie只能在http(https)请求上传递。也就是说httponly cookie对客户端脚本语言(javascript)无效,从而避免了跨站攻击时JS偷取cookie的情况。当你使用javascript在设置同样名字的cookie时,只有原来的httponly值会传送到服务器。
e.3rd-party cookie
第一方cookie是cookie种植在浏览器地址栏的域名或子域名下的。第三方cookie则是种植在不同于浏览器地址栏的域名下。例如:用户访问a.com时,在ad.google.com设置了个cookie,在访问b.com的时候,也在ad.google.com设置了一个cookie。这种场景经常出现在google adsense,阿里妈妈之类的广告服务商。广告商就可以采集用户的一些习惯和访问历史。
f.Super Cookie
超级cookie是设置公共域名前缀上的cookie。通常a.b.com的cookie可以设置在a.b.com和b.com,而不允许设置在.com上,但是很不幸的是历史上一些老版本的浏览器因为对新增后缀过滤不足导致过超级cookie的产生。
e.Zombie Cookie
僵尸cookie是指那些删不掉的,删掉会自动重建的cookie。僵尸cookie是依赖于其他的本地存储方法,例如flash的share object,html5的local storages等,当用户删除cookie后,自动从其他本地存储里读取出cookie的备份,并重新种植。
3.Cookie用途
a.会话管理
1.记录用户的登录状态是cookie最常用的用途。通常web服务器会在用户登录成功后下发一个签名来标记session的有效性,这样免去了用户多次认证和登录网站。
2.记录用户的访问状态,例如导航啊,用户的注册流程啊。
b.个性化信息
1.Cookie也经常用来记忆用户相关的信息,以方便用户在使用和自己相关的站点服务。例如:ptlogin会记忆上一次登录的用户的QQ号码,这样在下次登录的时候会默认填写好这个QQ号码。
2.Cookie也被用来记忆用户自定义的一些功能。用户在设置自定义特征的时候,仅仅是保存在用户的浏览器中,在下一次访问的时候服务器会根据用户本地的cookie来表现用户的设置。例如google将搜索设置(使用语言、每页的条数,以及打开搜索结果的方式等等)保存在一个COOKIE里。
c.记录用户的行为
最典型的是公司的TCSS系统。它使用Cookie来记录用户的点击流和某个产品或商业行为的操作率和流失率。当然功能可以通过IP或http header中的referrer实现,但是Cookie更精准一些。
4. Cookie的实现
Cookie是web server下发给浏览器的任意的一段文本,在后续的http 请求中,浏览器会将cookie带回给Web Server。同时在浏览器允许脚本执行的情况下,Cookie是可以被JavaScript等脚本设置的。
a. 如何种植Cookie
http方式:以访问http://www.webryan.net/index.php为例
Step1.客户端发起http请求到Server
GET /index.php HTTP/1.1
Host: www.webryan.net
(这里是省去了User-Agent,Accept等字段)
Step2. 服务器返回http response,其中可以包含Cookie设置
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value
Set-Cookie: name2=value2; Expires=Wed, 09 Jun 2021 10:18:14 GMT
(content of page)
Step3. 后续访问webryan.net的相关页面
GET /spec.html HTTP/1.1
Host: www.webryan.net
Cookie: name=value; name2=value2
Accept: */*
需要修改cookie的值的话,只需要Set-Cookie: name=newvalue即可,浏览器会用新的值将旧的替换掉。
脚本方式种植 Cookie:
JavaScript或类似的寄宿在浏览器中的脚本语言也可以设置Cookie。在JavaScript里,可以通过document.cookie对象实现。例如:
document.cookie = “key=newvalue”;
b. Cookie属性
除了name=value对以外,我们还可以设置Cookie其他属性以支持更丰富的Cookie需求,这些属性通常是浏览器用来判断如何对待cookie,何时删除、屏蔽或者如何发送name-value对给Server。也就是说无论我们设置了某个cookie的多少属性,这些Cookie属性是不会被浏览器发送回给Server的。
a) Domain and Path
作用:定义Cookie的生效作用域,只有当域名和路径同时满足的时候,浏览器才会将Cookie发送给Server。如果没有设置Domain和Path的话,他们会被默认为当前请求页面对应值。 举例如下:
提问下:第一个和第三个Cookie有啥不一样??
结论:浏览器优先匹配domain,而对于Path字段则是以匹配的方式进行判断。
对于 1.http://docs.foo.com/accounts/index.html
2.http://docs.foo.com/accountstest.html
1.会带上Cookie1,2,3; 2会带上1,2
b) Expires and Max-Age
作用:设置浏览器何时删除Cookie
Expires的规定格式是:“Wdy, DD-Mon-YYYY HH:MM:SS GMT”。
相对于Expires的精准的时间设置,在RFC 2965中规范提供了一个替代方案:Max-Age:seconds,来设置cookie在设置后多长秒后失效。
Set-Cookie: lu=Rg3vHJZnehYLjVg7qi3bZjzg; expires=Tue, 15-Jan-2013 21:47:38 GMT; path=/; domain=.foo.com; httponly
Set-Cookie: made_write_conn=1295214458; path=/; domain=.foo.com
Set-Cookie: reg_fb_gate=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.foo.com; httponly
第一个Cookie: 过期时间是2013年1月15日的精确时间;
第二个:没有设置过期时间,为Session cookie.
第三个:删除Cookie
C) Secure and HttpOnly
作用:设置Cookie的安全属性
特质:Secure和HttpOnly都是没有value字段的。
Secure字段告诉浏览器在https通道时,对Cookie进行安全加密,这样即时有黑客监听也无法获取cookie内容。
HttpOnly字段告诉浏览器,只有在HTTP协议下使用,对浏览器的脚本不可见,所以跨站脚本攻击时也不会被窃取。 从前面例子可以看到Google和Facebook都在使用HttpOnly的Cookie。
5. 浏览器相关
a) Cookie规范规定浏览器最少支持300个cookie,每个cookie 4kb;每个域名最少20个cookie。
b) 浏览器都支持删除和禁用cookie
c) 在浏览器地址栏输入:javascript:alert(document.cookie)可以看到所有cookie
d) 默认情况下,IE浏览器仅支持设置有P3P “CP” (Compact Policy) 标记的第三方Cookie.
测试方法:
javascript:for(var i=0;i<100;i++){document.cookie=’cookiename’+i+’=1aaa;’}document.cookie=’test=asdf;’;alert(document.cookie)
测试结论:ie8:每个域名50个,firefox:每个域名150个;chrome:每个域名170个;ie6、ie7:20个
测试方法:
javascript:var arr=[],i=5112;while(i){i–;arr.push(‘i’)}document.cookie=’test=’+arr.join(”)+’;';alert($.cookie.get(‘test’).length)
测试结论:
ie8:5112+5 = 5117
但最多10个大字段。字段内容多了的话,导致服务器无法响应。
6.Cookie窃取及会话劫持(hijacking)
相对很多Session验证方法的缺点和不足,大多数网站都是把Cookie当作用户的唯一标识。在这种情况下,黑客以可以通过窃取用户的cookie来模拟用户的请求行为,但对于服务器来说是无法辨别到底是来自用户还是黑客的。
下面给出Cookie作为用户标识的风险和安全隐患:
a. 网络监听
在网络上传输的数据都是会被监听获取的,尤其是在公共的、非加密的网络环境(free wifi)。这些数据也包括常规的http(非https加密通道)所有session,当然也就包括了HTTP 会话里的Cookie。当黑客拿到明文的cookie之后就可以模拟用户操作,比如改密码、消费等行为。
解决这个问题的最根本方法是采取https协议,通过SSL通道对内容及cookie进行加密。此外还有一些二次保护的方法可以作为过渡和折中。
b. DNS cache异常及其他
通过DNS cache或者DNS服务商的一些漏洞问题(www.baidu.com),黑客可以通过将www.baidu.com的子域名hack.www.baidu.com指向到黑客自己的IP。这样黑客就可以通过方式http://hack.www.baidu.com/a.png图片到公共环境,从而可以获取到baidu.com下的所有cookie,包括设置了HttpOnly属性的Cookie。
解决办法:1.减少dns无效配置 2.ISP服务商加强自我安全管理。3.通过HTTPS请求对请求进行加密和授权,这样黑客很难从凭证管理中心获得认证,那么用户在操作的时候会收到明显的提示。
c. 跨站脚本XSS—窃取Cookie
由于JavaScript等脚本语言可以读取页面文档内的Cookie值,同时又可以向任意服务器发出任意的请求。综合起来,黑客可以通过脚本将当前文档下的cookie据为己有。如果黑客使用的地址是https://attacker.com/stole.cgi,那么Secure Cookie也将以明文的方式发送个attacker.com.
跨站脚本是web安全永久不变的话题。Web开发者有责任去过滤掉恶意代码。同时,HttpOnly Cookies不可以被客户端脚本读取,这就大大降低了Cookie被盗取的风险。
d. 跨站脚本XSS—hijacking
当黑客可以在www.test.com上插入一段JS脚本的话,那么没有禁用JS的用户很轻易的会收到hijacking攻击。黑客利用用户的浏览器来发出HTTP请求到test.com本身,所以与用户相关的所有cookie都会存在(包括HttpOnly和Secure Cookie)。例如:人人网发生的分享蠕虫。
对于这种攻击,除了避免跨站脚本漏洞以外,可以采取验证码的方式进行一定程度上的规避。
e. 跨站脚本XSS—代理请求
老版本的浏览器允许用户使用XMLHttpRequest发出代理请求,黑客可以通过设置代理将本地的cookie全量的发给代理服务器,再从代理服务器转发给原始服务器。当然这是很快被禁止了。
f. 跨站请求伪造—CSRF
CSRF主要是黑客将伪造的请求URL放到一个图片或者其他静态资源里,这种成本极低,且传播性和形象力非常大。
举例:Qzone的签名的修改地址是:http://qzone.qq.com/cgi-bin/modify?nick=123
那么黑客将其并放到流量很大的论坛或者博客里。那么很多人就在不知情的情况下就执行了某些操作。
7. Cookie的缺点和不足
a) 被讨论最多的就是隐私问题
b) Cookie引入的各种安全问题
c) 与REST软件架构相背离。
d) 状态不一致,后退导致cookie不会重置。
c) 过多使用到是HTTP请求流量浪费
8.Cookie的取代方案
a) window.name
当前所有浏览器都能通过DOM结构中的window.name存储2-32MB的数据。同时window.name是跨域名,但是只能是在当前tab里使用,每个tab初始化后都是有个空的window.name。Window.name是可以传递对象的,所以我们通过将数据保存在json里进行传递和存储。
由于window.name不通过网络传送,所以不会存在被窃取的风险。同时所以从某种角度通过window.name进行用户行为分析更为合理,同时又不会像cookie一样引来http流量消耗
b.)Internet Explorer userData storage (starting IE9, userData is no longer supported)
支持:IE5-IE8
使用:
或者,通过脚本来设置:
object.style.behavior = “url(‘#default#userData’)”
object.addBehavior (“#default#userData”)
数据:
在XP下,一般位于C:\Documents and Settings\用户名\UserData,有些时候会在C:\Documents and Settings\用户名\Application Data\Microsoft\Internet Explorer\UserData。
在Vista下,位于C:\Users\用户名\AppData\Roaming\Microsoft\Internet Explorer\UserData
属性:expires 设置或者获取 userData behavior 保存数据的失效日期,不设置则为永久。
var store = document.documentElement;
store.addBehavior(‘#default#userdata’);
var STORE_NAME = ‘my_userdata’;
store.save(STORE_NAME);
store.setAttribute(‘a’, 123);
store.save(STORE_NAME);
store.load(STORE_NAME);
store.getAttribute(‘a’);
store.removeAttribute(‘a’);
store.save(STORE_NAME);
c)HTML5特性
• HTML5 Session Storage
• HTML5 Local Storage
• HTML5 Global Storage
• HTML5 Database Storage via SQLite
• Storing cookies in RGB values of auto-generated, force-cached PNGs using HTML5 Canvas tag to read pixels (cookies) back out
• Local Shared Objects (Flash Cookies)
• Silverlight Isolated Storage
d)Flash Shared Object
存在Flash的用户目录
依赖于flash的安装
使用数据量大100k,超过的需要用户允许
简单操作
var so:SharedObject = SharedObject.getLocal(key);
so.data.value = value;//return so.data.value
其他相关
RFC2109:
1.声明新增了Set-Cookie和Cookie两个HTTP头
2.延续使用HTTP/1.1的attribute-value对
3.Server可以在任意HTTP Header中设置cookie
4.Server可以设置多个Set-Cookie头
严格之处:
1.User Agent设置domain必须满足以.开头,且y.x.qq.com不能设置到.qq.com上
2.User Agent给服务器的是完整的Cookie
3.Netscape支持 Expires,协议支持max-age:
域名限制:
1.rfc要求
* at least 300 cookies
* at least 4096 bytes per cookie (as measured by the characters
that comprise the cookie non-terminal in the syntax description
of the Set-Cookie2 header, and as received in the Set-Cookie2
header)
* at least 20 cookies per unique host or domain name