Cookie相关总结

目录

前言

  本篇简单总结cookie的概念,作用,应用,实现案例等要点,关于大段的介绍,就不再重复了,网上有很多可以参考。而且cookie相关是一个很大的话题,这里只是简单小结,主要包括:
  1.cookie相关介绍
  2.cookie安全性问题
  3.javascript对cookie的操作与使用
  4.cookie与session的对比分析
  5.cookie在实际开发中的使用


直观感受

  cookie是一种存储在用户本地的数据。比如在windows系统中使用chrome浏览器访问网站,相应的数据将保存在如下目录:
C:\Users\gaochang\AppData\Local\Google\Chrome\User Data\Default
如图所示:

我们可以用一些第三方工具查看这个文件内容,比如chrome浏览器的一款插件cookies:

我们也可以在具体访问某个网站时,点击URL左边的“纸张/锁”图标,显示当前网站的cookie信息:


cookie相关介绍

定义

  Cookie是由服务器端生成的,当用户访问服务器后,发送给User-Agent(一般指浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie名称和值可以由服务器端在开发过程中自己定义,通过cookie服务器可以知道该用户是否是合法用户以及是否需要重新登录等,服务器可以设置或读取Cookies中包含信息,借此维护用户跟服务器会话中的状态。

标准

  cookie的规格标准文档主要有以下4种:
1.由网景公司颁布的规格标准
  网景通信公司设计开发了cookie,并制定了相关的规格标准。1994年前后,cookie正式应用在网景浏览器中。目前最为普及的cookie方式也是以此为准的。
2.RFC2109
  原本是想和网景公司的标准交互应用,可惜发生了微妙的差异。该标准现在已经淡出视线。
3.RFC2965
  为终结IE浏览器与Netscape Navigator的标准差异而导致的浏览器战争,该标准定义了新的HTTP首部Set-Cookie2和Cookie2。可事实上,并未投入大量使用。
4.RFC6265
  将网景公司制定的标准作为业界事实标准,重新定义cookie标准后的产物。

 目前使用最广泛的cookie标准并不是上述中的某一个,而是在网景公司制定的标准上进行扩展后的产物。

编码

  Cookies的值中可以保存除了“;”以外的标点符号。但是不能保存汉字。否则会出现乱码。所以对于Cookies中的内容要进行统一的编码和解码。为了在浏览器端和服务器端都能够进行解码和编码,可统一使用UTF-8编码格式。
  javacript提供了内置的编码和解码函数,用来将非英文的字符编码或者解码。编码函数为“escape”,使用语法如下
codedString=escape(originalString);
其作用为,将参数字符串“originalString”中的特殊字符(绝大多数的非英文字母、非数字的字符)替换为”%”加上该字符Unicode编码的两位十六进制字符,或者“%u”加上该字符unicode编码的4位十六进制字符(视该字符的编码而定);
  函数“un escape”与“escape”相反,用于将“escape”编码后的字符串还原为原始的字符串,其语法如下:
originalString=unescape(codedString);

属性

cookie主要的属性有:
 (1)name:Cookie名称,Cookie名称必须,一般用字母及数字,不能包含特殊字符,如有特殊字符需要转码。如js操作cookie的时候可以使用escape()对名称转码。

 (2)value:Cookie值,Cookie值同理Cookie的名称,可以进行转码和加密。

 (3)expire:过期日期,一个GMT格式的时间,当过了这个日期之后,浏览器就会将这个Cookie删除掉,当不设置这个的时候,Cookie在浏览器关闭(会话结束)后消失。

 (4)path:一个路径,在这个路径下面的页面才可以访问该Cookie,一般设为“/”,以表示同一个站点的所有页面都可以访问这个Cookie。

 (5)domain:子域,指定在该子域下才可以访问Cookie,例如要让Cookie在a.test.com下可以访问,但在b.test.com下不能访问,则可将domain设置成a.test.com。

 (6)secure:安全性,指定Cookie是否只能通过https协议访问,一般的Cookie使用HTTP协议即可访问,如果设置了secure,则只有当使用https协议连接时cookie才可以被页面访问。

 (7)httpOnly:如果在Cookie中设置了”HttpOnly”属性,那么通过程序(JS脚本、Applet等)将无法读取到Cookie信息。

分类

cookie主要可以分为以下两类:

Session cookies - these are temporary and are erased when you close your browser at the end of your surfing session. The next time you visit that particular site it will not recognise you and will treat you as a completely new visitor as there is nothing in your browser to let the site know that you have visited before.

会话cookie—这类cookie是短暂性的,是位于客户端所在系统的内存中的,当你的会话结束,关闭浏览器时,这类cookie将会被清空。当你下一次再访问该网站时,服务端并不能识别出你而是将你当做一个全新的用户,因为你的浏览器中没有任何可以让服务端判断你之前访问过的信息。(在设置了Discard参数(该参数是指当客户端程序运行结束时丢弃这个cookie。是RFC2965中新增字段,允许浏览器在退出时,不考虑过期时间,将cookie强制销毁),或者没有明确设置的expires或Max-Age的情况下,创建的是一个会话cookie。)主要作用:根据名字也容易看出,主要是为了配合服务端session机制对用户进行标识。

Persistent cookies - these remain on your hard drive until you erase them or they expire. How long a cookie remains on your browser depends on how long the visited website has programmed the cookie to last.

持久cookie—这类cookie将保存在客户端所在设备的硬盘上(具体位置见本文开头直观感受部分),除非你主动删除它们或者它们过期了。这类cookie能在你的浏览器中保持有效多长时间,取决于你所访问网站为之设定的有效期。主要作用:持久化cookie则主要是进行用户特征的追踪,比如记录用户最初访问时间,用户习惯等。

限制

  大多数浏览器支持最大为4096字节的 Cookie。浏览器还限制站点可以在用户计算机上存储的Cookie的数量。大多数浏览器只允许每个站点存储20个Cookie;注意这里的20个是指主键值,也就是20条Cookies记录,但是每个Cookies记录还可以包含若干子键。如果试图存储更多Cookie,则最旧的Cookie便会被丢弃。有些浏览器还会对它们将接受的来自所有站点的Cookie总数作出绝对限制,通常为300个。

传输

  cookie信息在浏览器(客户端)和服务器端的传递是通过http报文头部来实现的。
  HTTP请求报文的首部字段有“请求首部字段”,“通用首部字段”,“实体首部字段”3种;HTTP响应报文的首部字段有“响应首部字段”,“通用首部字段”,“实体首部字段”3种。具体到这里:为cookie服务的首部字段有:

首部字段名 说明 首部类型
Set-Cookie 开始状态管理所使用的Cookie信息 响应首部字段
Cookie 服务器接收到的Cookie信息 请求首部字段

下面具体来看一下两个字段:

Set-Cookie
示例:响应报文中的一段

Set-Cookie字段的属性有:

属性 说明
NAME=VALUE 赋予cookie的名称和值
expires=DATE cookie的有效期(若不明确指定则默认为浏览器关闭时)
path=PATH 指明服务器上的哪些文件目录作为cookie的适用对象
domain=域名 作为cookie适用对象的域名
Secure 仅在HTTPS安全通信时才会发送cookie,无具体值,直接指定“secure”即可
HttpOnly 加以限制,使cookie不能被js等脚本访问,无具体值,直接指定“HttpOnly”即可

Cookie
示例:请求报文中的一段

首部字段Cookie会告知服务器,当客服端想获得HTTP状态管理支持时,就会在请求头包含从服务器接收到的cookie。

案例

  下面是《HTTP权威指南》中给出的一个关于“cookie与会话跟踪”的例子:


修改

  其实cookie是不存在真正意义上的修改、删除操作的。要想修改,只需要在服务端新建一个同名cookie,填入http响应报文覆盖原来的cookie即可;要想删除,则只要在服务端新建一个同名cookie,并且设置maxAge为0,填入http响应报文覆盖原来的cookie即可。

作用

  cookie的作用主要在于“绑定一种状态”,其工作机制是用户识别及状态管理。比如购物网站中,一定时间内可以直接登录,免去输入用户名密码的繁琐;可以根据浏览记录精准推荐感兴趣的商品;正确记录购物车中已有商品等等。

小结

简单来讲,关于cookie记住3句话:
 1.首次由服务端生成,放入set-cookie字段传回给客户端;
 2.客户端请求报文首部加入该cookie;
 3.服务端识别该cookie,从而确定用户身份。


cookie安全性问题

  cookie在提供便利的同时,确实存在安全性问题,它可能被非法使用冒充身份。Cookie记录了用户的帐户ID、密码之类的信息,通常使用MD5方法加密后在网上传递。但是,Cookie以纯文本的形式在浏览器和服务器之间传送,很容易被他人非法截获和利用。并且截获者不需要知道这些字符串的含义,只要把别人的Cookie向服务器提交,且能够通过验证,就可以冒充受害人的身份登陆网站,这种行为就叫做Cookie欺骗。

httpOnly

  上述cookie属性中的httpOnly是安全性的解决方案之一。设置为true后,JavaScript是无法获取cookie的,可防止XSS(跨站脚本攻击)等。详见如下演示:
1.测试程序如下:

1
2
3
4
5
6
7
8
9
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index(){
setcookie("sid", "this is a cookie test", NULL, NULL, NULL, NULL, false);
$this->display();
}
}

根据setcookie()函数的API:

此时设置httpOnly的属性为false;客户端应该可以到sid=this is a cookie test这个cookie,验证代码:

1
2
3
4
5
6
7
<script>
$(function(){
$("#cookieBtn").click(function(){
alert(document.cookie);
})
})
</script>

点击“查看cookie信息”按钮,显示结果如下:

结果符合预期。

现在更改为true,开启httpOnly:

1
2
3
4
5
6
7
8
9
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index(){
setcookie("sid", "this is a cookie test", NULL, NULL, NULL, NULL, true);
$this->display();
}
}

点击“查看cookie信息”按钮,显示结果如下:

可以看出此时已经无法通过JavaScript获取cookie

但是,这种方式也还是有漏洞的,具体参见这篇文章:http://netsecurity.51cto.com/art/201404/435401.htm

httpOnly作用只是限制从其他非HTTP的API(如JavaScript)访问,cookie还是有可能传递的过程中被监听捕获后信息泄漏。将 HttpOnly 属性设置为 true,并不能防止对网络频道具有访问权限的攻击者直接访问该 Cookie。针对这种情况,应考虑使用安全套接字层 (SSL) 来提供帮助。
secure属性是防止信息在传递的过程中被监听捕获后信息泄漏。即:
setcookie("sid", "this is a cookie test", NULL, NULL, NULL, true, NULL);
HttpOnly属性的目的是防止程序获取cookie后进行攻击。即:
setcookie("sid", "this is a cookie test", NULL, NULL, NULL, NULL, true);


JavaScript对cookie的操作与使用

(注:以下内容主要为引用。)

应用场景

  JavaScript是运行在客户端的脚本,因此一般是不能够设置Session的,因为Session是运行在服务器端的。而cookie是运行在客户端的,所以可以用JS来设置cookie。假设有这样一种情况,在某个用例流程中,由A页面跳至B页面,若在A页面中采用JS用变量temp保存了某一变量的值,在B页面的时候,同样需要使用JS来引用temp的变量值,对于JS中的全局变量或者静态变量的生命周期是有限的,当发生页面跳转或者页面关闭的时候,这些变量的值会重新载入,即没有达到保存的效果。解决这个问题的最好的方案是采用cookie(本地文件)来保存该变量的值,那么如何来设置和读取cookie呢?首先需要稍微了解一下cookie的结构,简单地说:cookie是以键值对的形式保存的,即key=value的格式。各个cookie之间一般是以“;”分隔。

JS设置cookie

1
2
3
4
5
function setCookie(c_name,value,expiredays){
var exdate=new Date();
exdate.setDate(exdate.getDate()+expiredays);
document.cookie=c_name+ "=" +escape(value)+((expiredays==null) ? "" : "; expires="+exdate.toGMTString());
}

JS获取cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getCookie(c_name){
if (document.cookie.length>0){
c_start=document.cookie.indexOf(c_name + "=");
if (c_start!=-1){
c_start=c_start + c_name.length+1;
c_end=document.cookie.indexOf(";",c_start);
if (c_end==-1) {
c_end=document.cookie.length;
}
return unescape(document.cookie.substring(c_start,c_end));
}
} else {
return "";
}

}

JS删除cookie

1
2
3
4
5
6
7
8
function delCookie(name){
var exp = new Date();
exp.setTime(exp.getTime() - 1); //删除cookie即设置expires为一个过去的时间
var cval=getCookie(name);
if(cval!=null){
document.cookie= name + "="+cval+";expires="+exp.toGMTString();
}
}

JS检查cookie

1
2
3
4
5
6
7
8
9
10
11
12
function checkCookie()
{

username=getCookie('username');
if (username!=null && username!=""){
alert('Welcome again '+username+'!');
}else {
username=prompt('Please enter your name:',"");
if (username!=null && username!=""){
setCookie('username',username,365);
}
}
}

注:jQuery库也提供了对cookie操作的封装。具体可参见http://www.php100.com/html/program/jquery/2013/0905/6028.html


cookie与session的对比分析

  关于session,则又是一大块内容。具体地将在后面的文章中单独总结。这里仅把一些资料中的对比内容加以总结。

1.Session是服务器端使用的一种记录客户端状态的机制,使用上比Cookie简单一些,相应的也增加了服务器的存储压力。

2.不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。

3.客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

4.当多个客户端执行程序时,服务器会保存多个客户端的Session。获取Session的时候也不需要声明获取谁的Session。Session机制决定了当前客户只会获取到自己的Session,而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。

5.cookie和session的共同之处在于:cookie和session都是用来跟踪浏览器用户身份的会话方式。

6.cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session。

7.可将登陆信息等重要信息存放为session;其他信息如果需要保留,可以放在cookie中。

8.虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为Session需要使用Cookie作为识别标志。HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名称中包含类似“SESSIONID”字样的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。该Cookie为服务器自动生成的,它的maxAge属性一般为–1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是由浏览器窗口内的链接、脚本等打开的新窗口除外,这类子窗口会共享父窗口的Cookie,因此会共享一个Session。(注意:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在链接上右击,在弹出的快捷菜单中选择“在新窗口中打开”时,子窗口便可以访问父窗口的Session。)

9.我们知道,客户端浏览器是可以禁用Cookie的(或者可能就不支持Cookie)那么在这种情况下,为了使用session达到相应效果,就要使用另一种技术:URL地址重写。URL地址重写是对客户端不支持Cookie的解决方案。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。

参考:
http://www.cnblogs.com/shiyangxt/archive/2008/10/07/1305506.html
http://blog.csdn.net/axin66ok/article/details/6175522
http://blog.csdn.net/fangaoxin/article/details/6952954


cookie在实际开发中的使用

  根据上述cookie与session的对比分析可知,实际应用中cookie要配合session使用才能更好保证安全性。因此具体开发中的应用将在session相关总结一文中一并分析。


总结

  cookie相关内容十分丰富,这里只是对目前遇到的一些问题,根据网上已有资料和一些实际经验进行的总结,其中很多点都值得单独展开深入分析。