解析cookie



引言

在HTML出现初期,网页只包含一些文字和图片,客户端发出请求,服务器返回相应的内容,不需要区分这些请求来自哪个客户端。随着网络技术的发展,客户端与服务器之间的交互变得越来越复杂,服务器需要根据不同客户端的请求返回不同的内容,这首先要求服务器区分请求信息来自哪个客户端,于是,cookie应运而生,开始大行其道。

访问某站点时,客户端向服务器发出HTTP request,服务器返回HTTP response,如果该网站需要设置cookie,返回客户端的HTTP response中就包含Set-Cookie指令,客户端收到指令就会在系统中存储相应的cookie信息;当再次访问该站点时,客户端就会提取系统中存储的cookie信息,放在HTTP request中发给服务器,服务器根据cookie的“名称”和“值”,返回HTTP response。可见,cookie是服务器在客户端存储的数据,并以此跟踪和识别用户身份。

受HTTP header长度的限制,cookie一般都小于4096字节;同一站点存储在本地系统的cookie数量最多为20个,如果设置的cookie超过20个,最早的cookie会被删除。

[TOP]


cookie 组成

每一个cookie必须有Name及其Value,除此之外还有几个可选属性,用于指定该cookie的可用性、可见性、安全性等,客户端必须处理这些cookie信息。

Expires 过期时间

Expires值为绝对时间,如果客户端无法解析出时间,就会忽略Expires属性;当同一个cookie两次请求的Expires值不相同时,新的可能会替换旧的。

Max-Age 生存周期

指定cookie的有效时间,单位为秒;正数n表示该cookie在n秒后失效,负数表示关闭浏览器即失效,0表示删除该cookie,默认为-1;如果这个值不是数字,就忽略该属性。

Max-Age和Expires用于指定cookie的有效时间,如果这两个属性同时被指定,以Max-Age为准;如果这两个属性都没有指定,cookie只在浏览器会话期间有效。

Path

指定服务器端与cookie关联的网页路径,默认情况下,cookie会和创建它的网页、同级目录下的网页、子目录下的网页关联。

Domain

指定可使用该cookie的域,默认值为创建cookie的网页所在服务器的主机名,如Domain设置在服务器域之外,将导致cookie失效。

Secure

指定是否只通过HTTPS传输该cookie,默认为FALSE。

HttpOnly

指定是否只能通过HTTP访问该cookie,主要是为了防止通过XSS读取或修改cookie信息。

[TOP]


生成 cookie

通常cookie值是在服务端设置的,但也可以通过javascript在客户端设置,此外,编码方式(Java中的httpclient包)的HTTP request可以直接在header加入cookie;iOS的UIWebview可以在loadRequest构造带cookie的reqeust;Android的Webview可以通过CookieManager来设置cookie等等。

[TOP]


cookie 传输

cookie通过HTTP header传输,从服务器到客户端,response header中含有所有cookie属性:

Set-Cookie: NAME=VALUE; Expires=DATE; Path=PATH; Domain=DOMAIN_NAME; SECURE; HTTPONLY

从客户端到服务器,request header只发送cookie的Name和Value:

Cookie: NAME1=VALUE1; NAME2=VALUE2; NAME3=VALUE3

注意,服务器仅依据cookie的Name和Value区分客户端或用户。

[TOP]


cookie 文件

不同客户端保存cookie的形式不同,curl -c以Netscape格式保存cookie:

# Netscape HTTP Cookie File
# http://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

# Domain    Flag    Path    Secure  Expiration  Name    Value
.zhihu.com    TURE    /   FALSE   1451577601  q_c1  value
.weibo.cn	 TRUE    /   FALSE   1442218203  _T_WM   value

文件中每一行表示一个cookie,元素之间以制表符分隔。

Domain 可使用该cookie的域
Flag 是否允许所有子域使用该cookie
Path 服务器端,与该cookie关联的网页路径
Secure 是否需要安全连接(HTTPS)
Expiration 过期时间,以Unix时间戳表示
Name cookie名称
Value cookie值


Unix时间戳(Unix epoch, Unix time, POSIX time, Unix timestamp)是从1970年1月1日0时0分0秒(UTC/GMT)开始所经过的秒数,不考虑闰秒。在linux中可以方便地实现时间戳与普通时间的转换:

$ date +%s -d"2016-01-01 00:00:01"
1451577601
$ date -d @1451577601
[...]

IE 的cookie保存在cookies目录下的txt文件中,文件名格式为:

用户名@域名[数字].txt

浏览器会通过该目录下index.dat中的索引信息定位cookie文件,并查找相应的cookie字段。

这些txt文件为unix格式,换行使用LF(0D),因此最好不要使用dos和windows自带编辑器(使用CR+LF即0D0A换行)打开这些文件。每一个文件中,包含多个cookie字段,字段之间以*分隔,每个字段8行,如:

q_c1
value
zhihu.com/
1600
1907785472
30089218
2153600368
29942367
*
_T_WM
value
weibo.cn/
1600
1015832320
29979080
2155320368
29942367
*
1 cookie名称
2 cookie值
3 可使用该cookie的域
4 可选标记,指定HttpOnly等属性
5 过期时间高位整数
6 过期时间低位整数
7 创建时间高位整数
8 创建时间低位整数


这里的过期时间和创建时间都以windows下的FILETIME表示,关于时间戳的转换,请Google “Date format converter”或者看这里

[TOP]


安全管理

cookie默认是明文保存的,为了安全,客户端只会让cookie创建网站访问,即便如此,cookie仍然有泄露的风险,如通过XSS脚本攻击就可以截获cookie信息,一旦获取到cookie,不需要使用用户名和密码,就可以冒充用户身份直接登陆网站。

为了保证cookie数据的保密性,以及不被伪造或者篡改,现在通常需要对cookie内容进行加密,加密方式一般使用对称加密(单密钥,如DES)或非对称加密(一对密钥,如RSA),密钥保存在服务器端,如果不能提供正确的密钥,就无法对数据进行解密,也无法伪造或篡改数据。此外,重要的cookie数据通常会设置HttpOnly属性,避免跨站脚本获取cookie,保证了cookie在客户端的安全性;还可以设置Secure为TRUE,这样cookie只会在HTTPS下传输,保证了cookie在服务器端的安全性。

[TOP]