前言
当我们打开浏览器的控制台,可以看到浏览器的本地存储有cookie
、localstorage
、sessionstorage
cookie 和 localstorage 和 sessionstorage 的区别:
1. 大小上
- cookie 限制在 4 KB 以内,比较小;
- localstorage、sessionstorage 都是在 5 MB 以内,比较大;
2. 生命周期上
- cookie 如果没有设置有效时间,那网页一关闭就没了;如果有设置有效时间,则有效期一到就消失;
- localstorage 可以是永久的,跟网页、窗口是否关闭无关;
3. 域名限制上
- 共同点:cookie、localstorage 和 sessionstorage 都遵循
同源策略
- cookie 通过设置 domain 属性可以让同主域下的不同
子域拿到父域
的 cookie - localstorage、sessionstorage 是
无法
让子域名继承
父域名的 localstorage 数据
4. 作用域上
- 共同点:cookie、localstorage 和 sessionstorage 都不能在不同浏览器之间共享
- 作用域大小对比:localstorage(不同窗口)> cookie(同一窗口不同Tab)> sessionstorage(同一窗口同一Tab)
5. 网络传输上
- cookie 会参与网络请求,每次都
被携带放在 HTTP 请求头
当中 - localstorage、sessionstorage 不参与网络请求,只在
本地
和浏览器之间传输
function set(key,value){
var curtime = new Date().getTime();//获取当前时间
localStorage.setItem(key,JSON.stringify({val:value,time:curtime}));//转换成json字符串序列
}
function get(key,exp)//exp是设置的过期时间
{
var val = localStorage.getItem(key);//获取存储的元素
var dataobj = JSON.parse(val);//解析出json对象
// 当前时间 - 减去存储的元素在创建时候设置的时间 ? 过期时间
if(new Date().getTime() - dataobj.time > exp) console.log("expires");//提示过期
else console.log("val=" + dataobj.val); // 未过期,拿出这个值
}
6. 应用场景上
- cookie 用于存个性化主题、账号、密码、token
- localstorage 可以用于存储一些永久的数据,如用户的注册时间
- sessionstorage 可以用于存储临时购物车数据
cookie
cookie 是什么
cookie是浏览器管理状态的一个文件
,可以用来存储一些数据
cookie 的存储内容
- 会话状态管理:
用户登录状态
、账号信息
、游戏分数
、购物车
、收藏夹
- 用户行为分析:
访问次数
、停留时长
- 个性化设置:
用户自定义主题
cookie 各属性(字段)解读
我们从该图可以观察到cookie的属性(字段)有name、value、domain、path、expires、max-age、size、HttpOnly、Samesite、Secure、Priority
name (cookie的名字)
这个显而易见,就是代表cookie的名字
的意思,一个域名下
绑定的cookie,name不能相同
,否则相同的name的值会被覆盖掉
value (cookie的值)
这个就是每个cookie拥有的一个属性,它表示cookie的值
由于cookie规定是名称/值是`不允许包含分号,逗号,空格的`
所以为了不给用户到来麻烦,考虑服务器的兼容性,任何存储cookie的数据都应该被编码
// 例如将cookie中name为 tz 设置为 广东;shenzhen, 有中文也有分号, 就需要编码
document.cookie=`tz=${encodeURIComponent('广东;shenzhen')}`
console.log(document.cookie)
// tz=%E5%B9%BF%E4%B8%9C%3Bshenzhen
console.log(decodeURIComponent(document.cookie))
// tz=广东;shenzhen
domain (针对主域相同、子域不同的情况)
domain表示的是cookie绑定的域名
domain 应用场景:跨子域
- www.baidu.com 和 image.baidu.com 是属于
同主域下的不同子域
的两个网站,不满足同源策略
,所以不能共享cookie - 但如果这两个网站的cookie的
domain
属性都设置为.baidu.com
,那么所有
以".baidu.com"结尾的域名网站都可以共享该Cookie
path(同域下不同路径的文件)
path表示 cookie所在的目录
- cookie规定:path路径下的页面可以访问,path以上或以外路径的页面不可以访问
举例:
- 在同一个服务器上有目录如下:
/test
,/test/1
,/test/2
- cookie1的path为
/test/
, cookie2的path为/test/1
test下
的所有页面都可以
访问到cookie1,/test/和/test/2
的子页面不能访问
cookie2
expires/max-age
- expires表示[
过期时间
],一个具体的时间字符串
,但已经逐渐被max-age所替代,原因有:- 【格式问题】expires属性首先需要将时间日期转换为GMT/UTC格式,否则某些浏览器可能会出现误差
- 【时间差】浏览器与服务器之间的时间可能存在时间差,因此也会造成出错
- max-age表示[
有效期
],采用max-age需要注意的点:- max-age的值是一个数字,单位是(s),表示这个cookie的有效时间
- 兼容性问题:目前chrome、Firefox等现代浏览器是支持max-age的,但IE是不支持max-age的 那如何解决兼容性问题又保证不出差错呢?
我想到的方法是:根据max-age设置cookie的过期时间,注意:服务端传过来的是max-age,但前端存的是expires,所以需要换算一下
function setCookie(name,value,maxage){
var date = new Date()
date.setDate(date.getTime()+maxage*1000)
document.cookie="name=" + name + "; expires=" + date + "; path=/; domain=.baidu.com"
}
secure(只在 HTTPS 下传输)
- 这个属性译为安全,http是不安全的协议,容易被劫持,当这个属性设置为true时,此cookie
只会
在https
和ssl
等安全协议下传输 - 这个属性并不能对客户端的cookie进行加密,不能保证绝对的安全性,仍然可能被窃取或冒用 HTTP和HTTPS的详细内容见 计算机网络系列 -- HTTP 和 计算机网络系列 -- HTTPS
HttpOnly(只在 http 请求中携带但不能读写)
如果这个属性设置为 true,则只有在 http 请求头中才会携带此 cookie 的信息,但不能通过document.cookie 来访问此cookie,能有效的防止 XSS 攻击
SameSite(不认第三方 cookie、只认第一方cookie)
Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击
和用户追踪
- Strict [最严格]
Strict最为严格,完全`禁止第三方 Cookie`,跨站点时,`任何情况下`都不会发送 Cookie。
换言之,只有当前网页的 URL 与请求目标`一致`,才会带上 Cookie
- Lax [稍放宽] 【默认值】
大多数情况也是不发送第三方 Cookie,但是导航到`目标网址的 Get 请求`除外
导航到目标网址的 GET 请求,只包括三种情况:链接
、预加载请求
、GET 表单
- None [完全开启]
同站请求、跨站请求都会携带cookie了 意味着有可能会受到攻击
cookie 的特点
1. 有保质期
- 会话 cookie:没有指定
Expires
或Max-Age
指令,其Expires/Max-Age字段的值为Session
- “永久” cookie:有指定
Expires
或Max-Age
指令,其Expires/Max-Age字段的值为一个具体时间字符串
2. 满足同源策略
- 同源策略下的网站
共享
cookie - 不满足同源策略下的网站
无法共享
cookie 这里的“共享”是指获取、更改
,但不包括请求时被携带
满足同源策略下:在`path`指定的`路径及其下目录`(子网页的意思)的页面都可以获取,否则不可以获取
不满足同源策略下:在`domain`指定的`主域下的所有子域`可以获取,否则就不可以获取
为什么说 不包括请求时被携带
,又为什么 cookie不可跨域 还会 遭受CSRF攻击 呢?
这是因为:网站B可以想网站A发送任何一个请求,而这个http请求中的请求头是`可以携带`网站A的cookie的
因为浏览器是`看请求域名携带cookie的`(CSRF攻击就是利用这个漏洞),这与cookie不可跨域`并不冲突`
`cookie不可跨域`是指:在网站B下,只能读取网站B的cookie而不能读取网站A的cookie
3. 内存大小受限
Cookie有个数和大小的限制,大小一般是4k
4. 安全性不高
cookie 在本地可以被更改,也可以被获取,也可以被冒用
敏感的数据不要放在cookie里
同一个域名下的所有请求,都会自动携带 Cookie
cookie 的缺点
- 容量方面:有上限,最大只能有 4KB
- 性能方面:同一个域名下的所有请求,都会携带 Cookie,某些请求(a,img,link等标签发出的请求)可能不需要此cookie,会加大传输的头部,
损耗一定时空开销
- 安全问题:客户端可以通过一定手段(脚本,devtools,本地存储的文件,修改host文件)获取到,存在XSS,CSRF等
安全问题
解决安全问题的方案
- 减短cookie的有效时间
- 设置HttpOnly属性:防止本地脚本读取cookie,可防止
XSS 攻击
- 设置samesite属性:严格卡控cookie的携带范围,可防止
CSRF 攻击
- 服务端对传送的cookie加密
- 添加Secure属性:使用https协议传输 前端安全的详细内容具体见 浏览器系列 -- 前端安全
cookie 存放的位置
会话cookie:存放在浏览器内存当中 永久cookie:存放在本地硬盘当中
比如:Chrome浏览器的cookie就保存在C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default\Cookies.txt
cookie 的创建及使用
服务端下发cookie
第一次访问网站的时候,浏览器发出请求,服务器响应请求后,会将cookie放入到响应请求中
前端创建cookie
前端收到服务器发送过来的HTTP报文后
// 以报文里Set-Cookie里的内容为准设置cookie,该函数可以封装起来
function setCookie(name,value,maxage){
var date = new Date()
date.setDate(date.getTime()+maxage*1000)
document.cookie="name=" + name + "; expires=" + date + "; path=/; domain=.baidu.com"
}
这里注意,全部cookie是一个字符串,每个cookie之间用"; "
(分号+空格)隔开
前端获取 cookie
浏览器第二次请求时会携带cookie
1. 前端JavaScript先获取cookie里的内容
如:var x = document.cookie;
JavaScript中写上述代码即可读取,注意返回的是全部cookie组成的一长串字符串
2. 从字符串中读取`expires/max-age`的值来判断当前cookie是否有效
// 将字符串形式转化为object形式并取值
function cookie(name){
var cookieArray = document.cookie.split("; "); //得到分割的cookie名值对
var cookie = new Object();
for (var i=0;i<cookieArray.length;i++){
var arr = cookieArray[i].split("="); //将名和值分开
if(arr[0]==name) return decodeURIComponent(arr[1]); //如果是指定的cookie,则返回它的值
}
return "";
}
这里注意:当使用encodeURIComponent()
编码后,在取出值以后需要使用decodeURIComponent()
进行解码才能得到原来的cookie值
前端更新 cookie
我们是通过服务端的Set-Cookie对cookie进行增删改的,所以服务端每次更新cookie,前端都要同步更新
JavaScript 在设置 cookie 时会遵循这样一条原则:新设置的 cookie 如果与原有的 cookie 相同(名称、路径和域名都相同
),会将原有的 cookie 覆盖
根据这条原则我们更新cookie的时候注意指明:要修改cookie的 名称、路径和域名
前端删除cookie
document.cookie="expires=Thu, 01 Jan 1970 00:00:00 GMT";
// 设置过期时间为过去的时间即可
document.cookie="max-age=0";
// 设置有效期为0也可以
document.cookie="max-age=-1"; 【max-age的默认值是-1,这也就对应了没有设置expires和max-age属性就cookie默认为会话cookie】
// 设置为负数表示让cookie变成会话cookie,浏览器一关对应的cookie就没了