HTTP cookies 详解

 
标签: httpcookies
 分类:

    HTTP cookies,一般又称做"cookies",已经存在了很长时间,可是仍旧没有被予以充分的理解。首要的问题是存在了诸多误区,认为cookies是后门程序或病毒,或压根不知道它是如何工做的。第二个问题是对于cookies缺乏一个一致性的接口。尽管存在着这些问题,cookies仍旧在web开发中起着如此重要的做用,以致于若是cookie在没有可替代品出现的状况下消失,咱们许多喜欢的Web应用将变得毫无用处。javascript

       cookies的起源php

       早期Web开发面临的最大问题之一是如何管理状态。简言之,服务器端没有办法知道两个请求是否来自于同一个浏览器。那时的办法是在请求的页面中插入一个token,而且在下一次请求中将这个token返回(至服务器)。这就须要在form中插入一个包含token的隐藏表单域,或着在URL的qurey字符串中传递该token。这两种办法都强调手工操做而且极易出错。html

       Lou Montulli,那时是网景通信的一个雇员,被认为在1994年将“magic cookies”的概念应用到了web通信中。他意图解决的是web中的购物车,如今全部购物网站都依赖购物车。他的最先的说明文档提供了一些cookies工做原理的基本信息该文档在RFC2109中被规范化(这是全部浏览器实现cookies的参考依据),而且最终逐步造成了REF2965.Montulli最终也被授予了关于cookies的美国专利。网景浏览器在它的第一个版本中就开始支持cookies,而且当前全部web浏览器都支持cookies。前端

       cookie是什么?java

       坦白的说,一个cookie就是存储在用户主机浏览器中的一小段文本文件。Cookies是纯文本形式,它们不包含任何可执行代码。一个Web页面或服务器告之浏览器来将这些信息存储而且基于一系列规则在以后的每一个请求中都将该信息返回至服务器。Web服务器以后能够利用这些信息来标识用户。多数须要登陆的站点一般会在你的认证信息经过后来设置一个cookie,以后只要这个cookie存在而且合法,你就能够自由的浏览这个站点的全部部分。再次,cookie只是包含了数据,就其自己而言并不有害。web

       建立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 高级程序设计》是一本高质量的前端技术著做。

相关文章
相关标签/搜索