乐趣区

Cookie和Session你不能不知道的秘密

1、cookie 是什么
由于 HTTP 是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是 Cookie 的工作原理。
Cookie 实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用 response 向客户端浏览器颁发一个 Cookie。客户端浏览器会把 Cookie 保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该 Cookie 一同提交给服务器。服务器检查该 Cookie,以此来辨认用户状态。服务器还可以根据需要修改 Cookie 的内容。如下图:
1.1、cookie 的属性

属性项
属性项介绍

Name
一个唯一确定 cookie 的名称(cookie 名称不区分大小写,实践中最好区分,因为一些服务器会区分),URL 编码

Value
存储 cookie 的字符串值,值必须经过 URL 编码

Expires
过期时间,在这个时间点后 Cookie 失效

Domain
生成 Cookie 域名

Path
该 Cookie 是在当前那个路径下生成的

Secure
加密设置,设置他之后,只会在 SSL 连接时才会回传该 Cookie

这里我只要说二个点:1、Expires: 该 Cookie 失效的时间,单位秒。

如果为正数,则该 Cookie 在 maxAge 秒之后失效(持久级别 Cookie)。
如果为负数,该 Cookie 为临时 Cookie,关闭浏览器即失效(会话级别 Cookie),浏览器也不会以任何形式保存该 Cookie。
如果为 0,表示删除该 Cookie。默认为–1;

2、Domain: 我们现在有二个域名。域名 A:b.f.com,域名 B:d.f.com;显然域名 A 和域名 B 都是 f.com 的子域名
如果我们在域名 A 中的 Cookie 的 domain 设置为.f.com,那么.f.com 及其子域名都可以获取这个 Cookie,即域名 A 和域名 B 都可以获取这个 Cookie
如果域名 A 没有显式设置 Cookie 的 domain 方法,那么 domain 就为.b.f.com,不一样的是,这时,域名 A 的子域名将无法获取这个 Cookie
HttpOnly: 这个属性是面试的时候常考的,如果这个属性设置为 true,就不能通过 js 脚本来获取 cookie 的值,能有效的防止 xss 攻击
1.2、cookie 的操作
由于 js 没有给原生的操作方法,我们可以简单地封装一下:
var cookieUtil = {
getItem: function (name) {
var cookieName = encodeURIComponent(name) + “=”,
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null;
if (cookieStart > -1) {
var cookieEnd = document.cookie.indexOf(‘;’, cookieStart);
if (cookieEnd == 1) {
cookieEnd = document.cookie.length;
}
cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd))
}
return cookieValue;
},
setItem: function (name, value, expires, path, domain, secure) {
var cookieText = encodeURIComponent(name) + “=” + encodeURIComponent(value);
if (expires) {
cookieText += “;expires=” + expires.toGMTString();
}
if (path) {
cookieText += “;path=” + path;
}
if (domain) {
cookieText += “;domain=” + domain;
}
if (secure) {
cookieText += “;secure”;
}
document.cookie = cookieText;
},
unset: function (name, path, domain, secure) {
this.setItem(name, “”, new Date(0), path, domain, secure)
}
}
CookieUtil.setItem(“name”, ‘tom’); // 设置 cookie
console.log(CookieUtil.getItem(‘name’));// 读取 cookie
CookieUtil.unset(“name”)// 删除 cookie
1.3、Cookie 防篡改机制
因为 Cookie 是存储在客户端,用户可以随意修改。所以,存在一定的安全隐患。
防篡改签名:服务器为每个 Cookie 项生成签名。如果用户篡改 Cookie,则与签名无法对应上。以此,来判断数据是否被篡改。
原理如下:

服务端提供一个签名生成算法 secret
根据方法生成签名 secret(wall)=34Yult8i
将生成的签名放入对应的 Cookie 项 username=wall|34Yult8i。其中,内容和签名用 | 隔开。
服务端根据接收到的内容和签名,校验内容是否被篡改。

举个栗子:比如服务器接收到请求中的 Cookie 项 username=pony|34Yult8i,然后使用签名生成算法 secret(pony)=666。算法得到的签名 666 和请求中数据的签名不一致,则证明数据被篡改。
2、Session
Session: 是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中. 为了获得更高的存取速度,服务器一般把 Session 放在内存里。每个用户都会有一个独立的 Session。如果 Session 内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session 里的信息应该尽量精简。
当客户端请求创建一个 session 的时候,服务器会先检查这个客户端的请求里是否已包含了一个 session 标识 – sessionId,

如果已包含这个 sessionId,则说明以前已经为此客户端创建过 session,服务器就按照 sessionId 把这个 session 检索出来使用(如果检索不到,可能会新建一个)
如果客户端请求 (一般是通过 cookie 携带) 不包含 sessionId,则为此客户端创建一个 session 并且生成一个与此 session 相关联的 sessionId

sessionId 的值一般是一个既不会重复,又不容易被仿造的字符串,这个 sessionId 将被在本次响应中返回给客户端保存。保存 sessionId 的方式大多情况下用的是 cookie。
session 的运行依赖 session id,而 session id 是存在 cookie 中的
如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做 URL 重写的技术来进行会话跟踪,(在 url 中传递 session_id)即每次 HTTP 交互,URL 后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
3、cookie 与 session 的区别

cookie
session

存储位置
客户端
服务器端

存取方式
只能保管 ASCII 字符串
够存取任何类型的数据

有效期不同
Cookie 可以设置过期时间属性
JSESSIONID 的过期时间默许为–1,只需关闭了阅读器该 Session 就会失效

服务器压力
Cookie 保管在客户端,不占用服务器资源。假如并发阅读的用户十分多,Cookie 是很好的选择
Session 是保管在服务器端的,每个用户都会产生一个 Session。假如并发访问的用户十分多,会产生十分多的 Session,耗费大量的内存

跨域支持上的不同
Cookie 支持跨域名访问,例如将 domain 属性设置为“.biaodianfu.com”,则以“.biaodianfu.com”为后缀的一切域名均能够访问该 Cookie。
Session 则不会支持跨域名访问。Session 仅在他所在的域名内有效。

区分路径
cookie 中如果设置了路径参数,那么同一个网站中不同路径下的 cookie 互相是访问不到的
session 不能区分路径,同一个用户在访问一个网站期间,所有的 session 在任何一个地方都可以访问到

如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star 对作者也是一种鼓励。
参考 Cookie 防篡改机制彻底理解 cookie,session,token

退出移动版