HTTP系列之Cookie
无状态协议
HTTP协议是无状态协议。HTTP协议自身不对请求和响应之间的通信状态进行保存。
于是为了实现期望的保持状态功能,引入了cookie技术。
Cookie
Cookie会根据从服务器端发送的响应报文内的Set-Cookie的首部字段信息,通知客户端保存Cookie。下次客户端再往该服务器发送请求时,自动在请求报文中加入Cookie再发送。
没有信息状态下的请求
存有信息状态下的请求
Set-Cookie
服务器端像客户端发送Cookie是通过HTTP响应报文实现的,在Set-Cookie中设置需要像客户端发送的cookie,cookie格式如下:
Set-Cookie: "name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2016 11:29:42 GMT;HttpOnly;secure"
其中name=value是必选项,其它都是可选项。
cookie特点
- 一个浏览器针对一个网站最多存20个Cookie,浏览器一般只允许存放300个Cookie
- 每个cookie的大小不能超过4KB。
- 通过HTTP协议的方式来存储数据。
- cookie会影响同一域名下的根目录及其子目录。
举例来说,如果当前URI是keithchou.github.io,如果设置path为'/'或者不设置(默认值为/),这个cookie对该域名的根路径和它的所有子路径都有效。如果path设置为/music,那么这个cookie只有在访问keithchou.github/music及其子路径才有效。 - 同源政策。
浏览器的同源政策规定,两个网址只要域名和端口相同,就可以共享cookie。注意,这里不要求协议相同。
cookie属性
Name
该Cookie的名称,一旦创建,名称便不可更改
value
该Cookie的值,如果值为Unicode字符,需要为字符编码,如果值为二进制数据,则需要使用BASE64编码
domain
可以访问该Cookie的域名。如果设置为”.google.com”,则所有以”google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”
这个domain稍作解释:
1. 非顶级域名,如二级域名或者三级域名,设置的cookie的domain只能为顶级域名或者二级域名或者三级域名本身,不能设置其他二级域名的cookie,否则cookie无法生成。 2. 顶级域名只能设置domain为顶级域名,不能设置为二级域名或者三级域名,否则cookie无法生成。 3. 二级域名能读取设置了domain为顶级域名或者自身的cookie,不能读取其他二级域名domain的cookie。所以要想cookie在多个二级域名中共享,需要设置domain为顶级域名,这样就可以在所有二级域名里面或者到这个cookie的值了。
顶级域名只能获取到domain设置为顶级域名的cookie,其他domain设置为二级域名的无法获取。
Path
path字段为可以访问此cookie的页面路径。 比如domain是abc.com, path是/detail,那么只有/detail 路径下的页面可以读取此cookie。
Expires/Max-Age:
1. 该Cookie失效时间,单位秒。如果为正数,则Cookie在maxAge秒之后失效。 2. 如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存Cookie. 3. 如果为0,表示删除Cookie。默认是-1
Size
cookie的大小
http
cookie的httponly属性。若此属性为true,则只有在http请求头中会带有此cookie的信息,而不能通过document.cookie来访问此cookie。
secure
设置是否只能通过https来传递此条cookie
cookie的分类
cookie有两种类型:
- 临时Cookie(会话Cookie)
- 永久Cookie
不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。可以类比于本地存储的sessionstore
设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。
存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存的cookie,不同的浏览器有不同的处理方式。可以类比于本地存储的localstore
cookie操作
获取
//读取cookie,一次性获取所有cookie。 console.log(document.cookie); //每个cookie都是以键值对的形式存在,并且通过;分隔。 "BAIDUID=9BD404162B2978E266B82B0D052A12D7:FG=1;BIDUPSID=605A0EB7E85170299BCFFF6C2B042840; "
设置
在cookie 的名或值中不能使用分号(;)、逗号(,)、等号(=)以及空格。在cookie的名中做到这点很容易,但要保存的值是不确定的。如何来存储这些值呢?方 法是用escape()函数进行编码,它能将一些特殊符号使用十六进制表示,例如空格将会编码为“20%”,从而可以存储于cookie值中,而且使用此种方案还可以避免中文乱码的出现。
document.cookie="str="+escape("I love ajax"); // document.cookie="str=I%20love%20ajax";
当使用escape()编码后,在取出值以后需要使用unescape()进行解码才能得到原来的cookie值
function setCookie(name,value) { var Days = 30; var exp = new Date(); exp.setTime(exp.getTime() + Days*24*60*60*1000); document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString(); }
修改
要想修改一个cookie,只需要重新赋值就行,旧的值会被新的值覆盖。但要注意一点,在设置新cookie时,path/domain这几个选项一定要旧cookie 保持一样。否则不会修改旧值,而是添加了一个新的 cookie。
删除
删除 cookie删除一个cookie 也挺简单,也是重新赋值,只要将这个新cookie的expires 选项设置为一个过去的时间点就行了。但同样要注意,path/domain/这几个选项一定要旧cookie 保持一样。
//获取当前时间 var date=new Date(); //将date设置为过去的时间 date.setTime(date.getTime()-10000); //将userId这个cookie删除 document.cookie="userId=828; expires="+date.toGMTString();
有一个坑,设置cookie时,和删除cookie时,必须要保持一模一样!!!
cookie安全性
登录时候用cookie的话,安全性问题怎么解决?
First:
把用户对象(包含了用户ID、用户名、是否登录..)序列化成字符串再加密存入Cookie。 密钥是:客户端IP+浏览器Agent+用户标识+固定的私有密钥 当cookie被窃取后,只要任一信息不匹配,就无法解密cookie,进而也就不能登录了。 这样做的缺点是IP不能变动、频繁加密解密会加重CPU负担
Second:
将用户的认证信息保存在一个cookie中,具体如下: 1.cookie名:uid。推荐进行加密,比如MD5(‘站点名称’)等。 2.cookie值:登录名|有效时间Expires|hash值。hash值可以由”登录名+有效时间Expires+用户密码(加密后的)的前几位 +salt” (salt是保证在服务器端站点配置文件中的随机数)
这样子设计有以下几个优点:
1.即使数据库被盗了,盗用者还是无法登录到系统,因为组成cookie值的salt是保证在服务器站点配置文件中而非数据 库。
2.如果账户被盗了,用户修改密码,可以使盗用者的cookie值无效。
3.如果服务器端的数据库被盗了,通过修改salt值可以使所有用户的cookie值无效,迫使用户重新登录系统。
4.有效时间Expires可以设置为当前时间+过去时间(比如2天),这样可以保证每次登录的cookie值都不一样,防止盗用者 窥探到自己的cookie值后作为后门,长期登录。
参考链接:聊一聊 cookie