HTTP Cookie详解
HTTP cookies,通常称之为“cookie”,已经存在很长时间了,但是仍然没有被充分理解。首要问题是存在许多误解,认为 cookie 是后门程序或病毒,却忽视了其工作原理。第二个问题是,对于 cookie 的操作缺少统一的接口。尽管存在这些问题,cookie 仍旧在 Web 开发中扮演者重要的角色,以至于如果没有出现相应的代替品就消失的话,我们许多喜欢的 Web 应用将变的不可用。
Cookie的起源
早期的 Web 应用面临的最大问题之一就是如何维持状态。简言之,服务器无法知道两个请求是否来自于同一个浏览器。当时,最简单的办法就是在请求的页面中插入一个 token,然后在下次请求时将这个 token 返回至服务器。这需要在页面的 form 表单中插入一个包含 token 的隐藏域,或者将 token 放在 URL 的 query 字符串中来传递。这两种方法都需要手动操作,而且极易出错。
当时网景通讯的一名员工 Lou Montulli,在 1994 年将 “magic cookies” 的概念应用到 Web 通讯中。他试图解决 Web 的第一个购物车应用,现在购物车成了购物网站的支柱。他的原始说明文档提供了 cookie 工作原理的基本信息,该文档后来被作为规范纳入到 RFC 2109(大多数浏览器的实现参考文档)中,最终被纳入到 RFC 2965 中。Montulli 也被授予 cookie 的美国专利。网景浏览器在它的第一个版本中就开始支持 cookie,现在所有 Web 浏览器都支持 cookie。Cookie是什么
简单地说,cookie 就是浏览器储存在用户电脑上的一小段文本文件。cookie 是纯文本格式,不包含任何可执行的代码。一个 Web 页面或服务器告知浏览器按照一定规范来储存这些信息,并在随后的请求中将这些信息发送至服务器,Web 服务器就可以使用这些信息来识别不同的用户。大多数需要登录的网站在用户验证成功之后都会设置一个 cookie,只要这个 cookie 存在并可以,用户就可以自由浏览这个网站的任意页面。再次说明,cookie 只包含数据,就其本身而言并不有害。创建Cookie
Web 服务器通过发送一个称为 Set-Cookie 的 HTTP 消息头来创建一个 cookie,Set-Cookie 消息头是一个字符串,其格式如下(中括号中的部分是可选的):
Set-Cookie:value[;expires=date][;domain=domain][;path=path][;secure]
消息头的第一部分,value 部分,通常是一个 name=value
格式的字符串。事实上,这种格式是原始规范中指定的格式,但是浏览器并不会对 cookie 值按照此格式来验证。实际上,你可以指定一个不含等号的字符串,它同样会被存储。然而,最常用的使用方式是按照 name=value
格式来指定 cookie 的值(大多数接口只支持该格式)。
当存在一个 cookie,并允许设置可选项,该 cookie 的值会在随后的每次请求中被发送至服务器,cookie 的值被存储在名为 Cookie 的 HTTP 消息头中,并且只包含了 cookie 的值,忽略全部设置选项。例如:
Cookie:value
服务器端框架通常包含解析 cookie 的方法,可以通过编程的方式获取 cookie 的值。
在Java的服务器应用程序中,Cookie[] cookies = request.getCookies();
Cookie编码
对于 cookie 的值进行编码一直都存在一些困惑。普遍认为 cookie 的值必须经过 URL 编码,但其实这是一个谬论,尽管通常都这么做。原始规范中明确指出只有三个字符必须进行编码:分号、逗号和空格,规范中还提到可以进行 URL 编码,但并不是必须,在 RFC 中没有提及任何编码。然而,几乎所有的实现都对 cookie 的值进行了一系列的 URL 编码。对于name=value
格式,通常会对 name 和 value 分别进行编码,而不对等号 = 进行编码操作。cookie设置选项
过期时间选项
紧跟 cookie 值后面的每个选项都以分号和空格分开,每个选择都指定了 cookie 在什么情况下应该被发送至服务器。第一个选项是过期时间(expires),指定了 cookie 何时不会再被发送至服务器,随后浏览器将删除该 cookie。该选项的值是一个Wdy, DD-Mon-YYYY HH:MM:SS GMT
日期格式的值,例如:Set-Cookie:name=Nicholsa;expires=Sat,02 May 2009 23:38:25 GMT
在Java代码中设置过期时间:
cookie.setMaxAge()
如果不设置该值,默认是会话期间有效。就是一个会话cookie。将这个值设置为-1,则会永久有效。domain选项
domain,指定了 cookie 将要被发送至哪个或哪些域中。默认情况下,domain 会被设置为创建该 cookie 的页面所在的域名,所以当给相同域名发送请求时该 cookie 会被发送至服务器。例如,本博中 cookie 的默认值将是 bubkoo.com。domain 选项可用来扩充 cookie 可发送域的数量,例如:Set-Cookie: name=Nicholas; domain=nczonline.net
设置domain为.XXX.com
像Yahoo! 这种大型网站,都会有许多 name.yahoo.com 形式的站点(例如:my.yahoo.com, finance.yahoo.com 等等)。将一个 cookie 的 domain 选项设置为
.yahoo.com
,就可以将该 cookie 的值发送至所有这些站点。浏览器会把 domain 的值与请求的域名做一个尾部比较(即从字符串的尾部开始比较),并将匹配的 cookie 发送至服务器。服务器设置domain的时候不能跨域。
设置的domain值,必须是客户端请求头中host的一部分。否则会有安全问题。不合法的domain会被客户端浏览器直接忽略掉。不能跨域,不仅不能设置别人的域名,也不能在用IP地址请求的时候,为该IP地址绑定的域名进行种cookie。也会被忽略。
path选项
另一个控制 Cookie 消息头发送时机的选项是 path 选项,和 domain 选项类似,path 选项指定了请求的资源 URL 中必须存在指定的路径时,才会发送Cookie 消息头。这个比较通常是将 path 选项的值与请求的 URL 从头开始逐字符比较完成的。如果字符匹配,则发送 Cookie 消息头,例如:
Set-Cookie:name=Nicholas;path=/blog
在这个例子中,path 选项值会与 /blog,/blogrool 等等相匹配;任何以 /blog 开头的选项都是合法的。需要注意的是,只有在 domain 选项核实完毕之后才会对 path 属性进行比较。path 属性的默认值是发送 Set-Cookie 消息头所对应的 URL 中的 path 部分。
secure选项
最后一个选项是 secure。不像其它选项,该选项只是一个标记而没有值。只有当一个请求通过 SSL 或 HTTPS 创建时,包含 secure 选项的 cookie 才能被发送至服务器。这种 cookie 的内容具有很高的价值,如果以纯文本形式传递很有可能被篡改,例如:Set-Cookie: name=Nicholas; secure
事实上,机密且敏感的信息绝不应该在 cookie 中存储或传输,因为 cookie 的整个机制原本都是不安全的。默认情况下,在 HTTPS 链接上传输的 cookie 都会被自动添加上 secure 选项。
3.Cookie 的维护和生命周期
4. 使用失效日期
5. Cookie自动删除
6. Subcookie
7. JavaScript中的cookie
8. Http-Only cookies
9. 小结
参考:
http://bubkoo.com/2014/04/21/http-cookies-explained/
http://www.ibm.com/developerworks/cn/java/j-cookie/