基础理论

cookie 是什么

  • 由 web 服务器端生成,发送给客户端(通常为浏览器)的一段文本,一旦收到 cookie 浏览器会将 cookie 的 key/value 保存到本地某个目录下的文本文件里。
  • 以后每次向服务器提交请求的时候,浏览器都会把存储的 cookie 发送到服务器,根据 cookie 中的值为访问的客户端提供数据。

为什么需要 cookie

  • 因为HTTP协议是无状态的,对于一个浏览器发出的多次请求,web 服务器无法区分是不是来源于同一个浏览器。所以,需要额外的数据用于维护会话。
  • cookie 就是让客户端积累一组服务器特有的信息,每次访问服务器时都将这些信息返回。

cookie 的限制

  • 大多数浏览器支持最大为 4096 字节的 cookie 。由于这限制了 cookie 的大小,最好用 cookie 来存储少量数据,或者存储用户 ID 之类的标识符。用户 ID 随后便可用于标识用户,以及从数据库或其他数据源中读取用户信息。
  • 浏览器限制站点可以在用户计算机上存储的 cookie 的数量。 cookie 最大长度和域名个数由不同浏览器决定,具体如下:
    浏览器 支持域名个数 最大长度
    IE7以上 50个 4095B
    Firefox 50个 4097B
    Opera 30个 4096B
    Safari/WebKit 无限制 4097B
    如果试图存储更多 cookie,则最旧的 cookie 便会被丢弃。有些浏览器还会对它们将接受的来自所有站点的 cookie 总数作出绝对限制,通常为 300 个。
  • 会话 cookie
    临时 cookie ,纪录用户访问站点时的设置和偏好。用户退出客户端,即被删除。
  • 持久 cookie
    存储在硬盘上,客户端退出,机器重启依然存在。通常用来维护某个用户会周期性访问的站点的配置文件或登录名。

可见它们的唯一区别就是过期时间。

这里只说浏览器这种客户端,不同的浏览器会以不同的方式来存储 cookie ,例如 chrome 的 cookie 存放在~/.config/browser-launcher2/google-chrome/Default/
在浏览器中可以用document.cookie读取及设置 cookie

浏览器内部的 cookie 罐中可以有成百上千个 cookie ,但浏览器不会将每个 cookie 都发送给所有的站点。实际上,它们通常只向每个站点发送2-3个 cookie

  • 对所有这些 cookie 字节进行传输会严重降级性能。浏览器实际传输的 cookie 字节数要比实际的内容字节数多。
  • cookie 中包含的是服务器特有的名值对,对于大部分站点来说大多数 cookie 都只是无法识别的无用数据。
  • 将所有的 cookie 发送给所有站点会引发潜在的隐私问题。

现在的 cookie 规范 rfc62655.2节 定义的 Set-Cookie Header ,除了必须包含 cookie 正文,还可以选择性包含6个属性
expires、domain、path、secure、max-age、httponly,它们之间用英文分号和空格 ; 连接。

响应头部:
Set-Cookie:name=value[;expires=data][;max-age=max-age-in-seconds;][;path=path][;domain=domain][;secure][; HttpOnly]

属性

  • NAME=VALUE
    强制。NAME 和 VALUE 都是字符序列,除非包含在双引号内,否则不包括分号、逗号、等号和空格。
  • Expires
    可选。这个属性指定一个日期字符串,用来定义 Cookie 的实际生存期。唯一合法的时区为 GMT ,各日期元素之间的分隔符一定要是长划线。超过这个时间,cookie 将消失,不可访问。如果没有指定 Expires , cookie 就会在用户会话结束时过期。
    格式 Sun, DD-Mon-YY HH:MM:SS GMT
  • Domain
    可选。浏览器只向指定域中的服务器主机名发送 cookie。如果没有指定域,就默认为产生 Set-Cookie 响应的服务器的主机名。
  • Path
    可选。通过这个属性可以为服务器上特定的文档分配 cookie 。如果 path 属性时一个 URL 路径前缀,就可以附加一个 cookie 。如果没有指定路径,这默认为’/‘,对此域名下的任何路径都可访问。
  • Secure
    可选。当设置为 true 时,表示创建的 cookie 会被以安全的形式向服务器传输,也就是只能在 HTTPS 连接中被浏览器传递到服务器端进行会话验证,如果是 HTTP 连接则不会传递该信息,所以不会被窃取到 cookie 的具体内容。在客户端我们无法在document.Cookie找到被设置了Secure=true的 cookie 键值对。 Secure 属性是防止信息在传递的过程中被监听捕获后信息泄漏,而下面的 HttpOnly 属性的目的是防止程序获取 cookie 后进行攻击。
  • Max-Age
    可选。这个属性的值是一个整数,用于设置以秒为单位的 cookie 生存期。 max-age 作为对 expires 的补充,现阶段有兼容性问题(IE低版本不支持),所以一般不单独使用。
  • HttpOnly
    可选。这是微软对 cookie 做的扩展。如果在 cookie 中设置了 HttpOnly 属性,那么通过程序(JS脚本、Applet等)将无法读取到 cookie 信息,这样能有效的防止 XSS 攻击。

测试

这里用nodejs为例,做个演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*先设置本地 hosts
sudo vi /etc/hosts
127.0.0.1 a.test.com
127.0.0.1 b.test.com
*/


var url = require('url');
var http = require('http');

http.createServer(function(req,res){
var urlObj = url.parse(req.url);
if('/favicon.ico' == urlObj.pathname){
res.writeHead(404);
res.end(http.STATUS_CODES[404]);
}else{
res.writeHead(200,{
"Set-Cookie":"name=llfly;path=/p;domain=a.test.com;expires=Sun, 08-Nov-2015 15:43:30 GMT";
});
res.end();
}
}).listen(8080);

chrome cookie查看

会看到只有在访问a.test.com:8080/p的情况下会存在 cookie ,因为是 GMT 时间,所以在 23:43:30 后会消失,而其他情况如localhost:8080/pb.test.com:8080/pa.test.com:8080无论任何时间都不存在 cookie ,证明了 path 和 domain 参数的作用。

主要用途

服务器可以利用 cookie 包含信息的任意性来筛选并经常性维护这些信息,以判断在 HTTP 传输中的状态。
cookie 最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续,这些都是 cookie 的功用。
另一个重要应用场合是“购物车”之类处理。用户可能会在一段时间内在同一家网站的不同页面中选择不同的商品,这些信息都会写入 cookie,以便在最后付款时提取信息。

参考

学习总结,主要参考:
http权威指南
深入潜出nodejs
RFC
你所不知道的HostOnly Cookie