在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必须有Name及其Value,除此之外还有几个可选属性,用于指定该cookie的可用性、可见性、安全性等,客户端必须处理这些cookie信息。
Expires值为绝对时间,如果客户端无法解析出时间,就会忽略Expires属性;当同一个cookie两次请求的Expires值不相同时,新的可能会替换旧的。
指定cookie的有效时间,单位为秒;正数n表示该cookie在n秒后失效,负数表示关闭浏览器即失效,0表示删除该cookie,默认为-1;如果这个值不是数字,就忽略该属性。
Max-Age和Expires用于指定cookie的有效时间,如果这两个属性同时被指定,以Max-Age为准;如果这两个属性都没有指定,cookie只在浏览器会话期间有效。
指定服务器端与cookie关联的网页路径,默认情况下,cookie会和创建它的网页、同级目录下的网页、子目录下的网页关联。
指定可使用该cookie的域,默认值为创建cookie的网页所在服务器的主机名,如Domain设置在服务器域之外,将导致cookie失效。
指定是否只通过HTTPS传输该cookie,默认为FALSE。
指定是否只能通过HTTP访问该cookie,主要是为了防止通过XSS读取或修改cookie信息。
[TOP]
通常cookie值是在服务端设置的,但也可以通过javascript在客户端设置,此外,编码方式(Java中的httpclient包)的HTTP request可以直接在header加入cookie;iOS的UIWebview可以在loadRequest构造带cookie的reqeust;Android的Webview可以通过CookieManager来设置cookie等等。
[TOP]
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的形式不同,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]