一文详解cookie, sessionStorage, localStorage

279 阅读11分钟

cookie

定义

cookie是由服务器发送给客户端(浏览器)的小量信息

作用

以键值对的形式存储少量信息,用于判断网络中的两个请求是否来自于同一个用户

一般接口使用无状态的HTTP协议传输数据,意味着客户端与服务端在数据传输完成后立刻通过四次挥手断开连接,每次连接都是独立存在的,没有任何状态将请求串联成一个整体,此时需要一个一直保持会话连接的机制,session出现之前,cookie就完全充当了这个角色,cookie存储的少量信息可以帮助跟踪会话,一般用来记录用户身份,也常记录跟踪购物车的商品信息及用户访问次数

原理

客户端请求服务器时,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。而客户端浏览器会把Cookie保存起来。当浏览器再请求服务器时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器通过检查该Cookie来获取用户状态

特点

  • 大小只有4kb,是纯文本文件,每次发起HTTP请求都会携带cookie
  • 创建成功后无法修改名称
  • 无法跨域名,能够阻止非法获取其他网站的cookie
  • 每个域名下cookie数量不能超过20个,每个cookie大小不能超过4kb
  • 存在安全问题,如果cookie被拦截,可以获得session所有信息,加密也于事无补,不需要知道cookie的意义,只要转发cookie就能达到目的

image.png

cookie的组成

  • Name:cookie的名称
  • Value:cookie的值,对于认证cookie,value包括web服务器所提供的访问令牌
  • Size:cookie的大小
  • Path:定义了可以访问此cookie的页面路径。使用JS只能读写当前路径和上级路径的Cookie,无法读写下级路径的Cookie
  • Secure:指定是否使用HTTPS安全协议发送cookie。使用HTTPS安全协议,可以保护Cookie在浏览器和Web服务器间的传输过程中不被窃取和篡改。该方法也可用于Web站点的身份鉴别,即在HTTPS的连接建立阶段,浏览器会检查Web网站的SSL证书的有效性。但是基于兼容性的原因(比如有些网站使用自签署的证书)在检测到SSL证书无效时,浏览器并不会立即终止用户的连接请求,而是显示安全风险信息,用户仍可以选择继续访问该站点。由于许多用户缺乏安全意识,因而仍可能连接到Pharming攻击所伪造的网站
  • Domain:指定了可以访问该cookie的域名,Cookie 机制并未遵循严格的同源策略,允许一个子域可以设置或获取其父域的Cookie。当需要实现单点登录方案时,Cookie 的上述特性非常有用,然而也增加了 Cookie受攻击的危险,比如攻击者可以借此发动会话定置攻击。因而,浏览器禁止在 Domain属性中设置.org、.com 等通用顶级域名、以及在国家及地区顶级域下注册的二级域名,以减小攻击发生的范围。使用JS只能读写当前域或父域的Cookie,无法读写其他域的Cookie
  • HTTP:该字段包含HTTPOnly 属性 ,该属性用于防止客户端脚本通过document.cookie属性访问Cookie,有助于保护Cookie不被跨站脚本攻击窃取,默认为空,即可以通过脚本访问。但是,HTTPOnly的应用仍存在局限性,一些浏览器可以阻止客户端脚本对Cookie的读操作,但允许写操作;此外大多数浏览器仍允许通过XMLHTTP对象读取HTTP响应中的Set-Cookie头
  • Expires/Max-size:cookie的失效时间,到达此时间后,此cookie失效。有两种存储类型的Cookie:会话性与持久性。Expires属性缺省时,为会话性Cookie(Session,意思是cookie会和session一起失效),仅保存在客户端内存中,并在用户关闭浏览器(不是浏览器标签页,而是整个浏览器)时失效;持久性Cookie会保存在用户的硬盘中,直至生存期到或用户直接在网页中单击“注销”等按钮结束会话时才会失效

当Name、Domain、Path这3个字段都相同的时候,才是同一个Cookie

服务器端可以使用 Set-Cookie 的响应头部来配置 cookie 信息

一条cookie 包括了5个属性值 expires、domain、path、secure、HttpOnly

domain 是域名、path是路径,domain 和 path 一起限制了 cookie 能够被哪些 url 访问

使用方法

//写入cookie: document.cookie = "key=value;";
setCookie(name,value,expiredays){//设置时间为天为过期单位
      var exdate=new Date();
      exdate.setDate(exdate.getDate()+expiredays);
      document.cookie=name + '=' + escape(value)+((expiredays==null) ? "" : ";expires="+exdate.toGMTString())
    },
//获取cookie:document.cookie
function getCookie(name){
    let reg=RegExp(name+'=([^;]+)');
    let arr=document.cookie.match(reg)
    if(arr){
        return arr[1];
    }else{
        return '';
    }
}
    //删除cookie:cookie 不能被删除,重写覆盖值
    function delCookie(name){
        setCookie(name,null,-1 )
    }

使用场景

  • 服务器在用户登录时生成用户唯一标识,即sessionId,并以映射表的形式保存在该台服务器的内存上(一般做法,也可以保存在其他地方),接着将该sessionId通过set-cookie头部传给客户端浏览器保存到 cookie,下次同源请求浏览器会携带sessionId给服务器,服务器再去查对应的用户id
  • 统计页面的点击次数

其它

token相对于cookie的优势

token是类似cookie的一种验证信息,客户端通过登录验证后,服务器会返回给客户端一个加密的token,当客户端再次向服务器发起连接请求时,带上token,服务器直接对token进行校验即可完成权限校验

  • 支持跨域访问:cookie存在跨域限制;token不存在跨域性质
  • 无状态(服务端可扩展行):Cookie 由于存储的内存空间只有4kb,因此存储的主要是一个用户id,其他的用户信息都存储在服务器的Session中。session需要在服务端存储,一般是通过cookie中的sessionID在服务端查找对应的session,由于所有用户都需要在服务器的 Session 中存储相对应的用户信息,所以如果用户量非常大,这对于服务器来说,将是非常大的性能压力;而token没有内存限制,用户信息可以存储在token中,返回给客户端自行存储
  • 去耦:不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可
  • 扩展性:当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多
  • CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范

cookie大小为什么限制4k

cookie的存储量小是因为cookie本身不是做存储的,主要是用来跟踪用户身份的

cookie过期时间如果不设置的话,是什么时间过期

没有指定Expires(过期时间)时,默认为会话Cookie,用户退出浏览器时,会话Cookie就被删除了

cookie的过期时间是由前端设置的吗

cookie一般由后端设置,并通过response流发送给前端并设置过期时间

设置什么字段能够使得js代码读取不到这个cookie

HttpOnly,该属性用于防止客户端脚本通过document.cookie属性访问Cookie,有助于保护Cookie不被跨站脚本攻击窃取

原生js获取cookie是如何获取的

    getCookie(cookie_name) {
        var allcookies = document.cookie;
        //索引长度,开始索引的位置
        var cookie_pos = allcookies.indexOf(cookie_name);
        // 如果找到了索引,就代表cookie存在,否则不存在
        if (cookie_pos != -1) {
            // 把cookie_pos放在值的开始,只要给值加1即可
            //计算取cookie值的开始索引,加的1为“=”
            cookie_pos = cookie_pos + cookie_name.length + 1;
            //计算取cookie值的结束索引
            var cookie_end = allcookies.indexOf(";", cookie_pos);
            if (cookie_end == -1) {
                cookie_end = allcookies.length;
            }
            //解码用escape方法进行了编码的 String 对象,得到想要的cookie的值
            var value = unescape(allcookies.substring(cookie_pos, cookie_end));
        }
        return value;
    }

如何配置跨域允许携带cookie?

需要解决3个问题

  1. 允许浏览器在发起跨域请求时携带类似证书、cookie、auth head等的信息(withCredentials)
  2. 服务端需要允许接受跨域请求(Access-Control-Allow-Origin)
  3. 服务端允许接受credentials类的信息(Access-Control-Allow-Credentials)

解决:

  1. XMLHttpRequest.withCredentials设置为true,放在axios中那就是config的withCredentials配置设置为true
  2. 服务端设置responseHeader中的Access-Control-Allow-Origin为来源域(也可以简单粗暴设置为*)
  3. 服务端设置responseHeader中的Access-Control-Allow-Credentials为true

在子域和域之间共享cookie

只有在set-cookie标头中显式命名域时,mydomain.comsubdomain.mydomain.com两个域才能共享cookie。否则,cookie的作用域将限于请求主机。(这被称为“仅限主机的cookie”)

如果您从subdomain.mydomain.com发送了以下标头,则不会为对mydomain.com的请求发送cookie:

Set-Cookie: name=value

但是,如果您使用以下内容,则它将在两个域上都可用:

Set-Cookie: name=value; domain=mydomain.com

登录,token或者cookie是存放在哪里的呢?如果是想实现15天免登录怎么做,token或者cookie放在哪里

待更新...

Web storage

web Storage的功能和cookie相似,区别在于

  1. web Storage更够储存更多的数据
  2. cookie会自动传递到服务器,浪费了带宽
  3. cookie需要指定作用域,不可跨越调用

HTML5增加了两个储存方式:sessionStorage和localStorage

sessionStorage

特点

只在当前会话下有效:

  • 在同源的同窗口中,只要不关闭浏览器,即使刷新或进入另一个同源页面,数据始终存在
  • 打开另一个窗口,即使是同一个页面,sessionStorage对象都不相同
  • 关闭窗口,sessionStorage被销毁

使用方法

      // 设置sessionStorage保存到本地,第一个为变量名,第二个是值
      sessionStorage.setItem('msg', 'seesion')
      // 获取数据
      sessionStorage.getItem('msg')
      // 删除保存的数据
      sessionStorage.removeItem('msg')
      // 清除所有保存的数据
      sessionStorage.clear()

image.png

使用场景

  • 存储网站游客登录信息
  • 存储临时的浏览记录信息

localStorage

特点

  • 优点
    • 存储大小:一般为5MB,可以存储更多信息
    • 数据有效期:localStorage持久存储,浏览器关闭后,除非主动删除数据,否则数据不会丢失
    • 仅存储在本地,不像cookie每次http请求都会被携带
  • 缺点
    • 浏览器兼容:IE8以下版本的浏览器不支持
    • 读取限制:如果浏览器设置为隐私模式,无法读取到localStorage
    • 访问限制:localStorage受同源策略限制,端口,协议,主机地址有任一不同都不会访问

使用方法

      //设置localStorage保存到本地,第一个为变量名,第二个是值
      localStorage.setItem('msg', 'value')
      // 获取数据
      localStorage.getItem('msg')
      // 删除保存的数据
      localStorage.removeItem('msg')
      // 清除所有保存的数据
      localStorage.clear()

以键值对的形式存储使用,并且只能是字符串类型,如果不是字符串类型,也会先自动转化为字符串类型再存进去

image.png

使用场景

  • 存储换肤信息
  • 存储网站不经常变动的个人信息
  • 存储用户用户浏览信息

其它

localStorage存储的信息能窃取到吗

待更新...

区别

相同点

都存储在浏览器端且同源

不同点

  • 存储大小限制不同:cookie数据大小不能超过4kb,sessionStorage和localStorage存储比cookie大得多,可以达到5M+
  • 数据有效期不同:cookie生存时间由expires属性指定,设置的过期时间之前一直有效;localStorage持久存储,浏览器关闭后,除非主动删除数据,否则数据不会丢失;sessionStorage数据在当前浏览器窗口关闭后自动删除
  • 作用域不同:cookie在所有同源窗口共享;localStorage也是在所有同源窗口共享;sessionStorage不在不同浏览器窗口共享,只能被同一个窗口的同源页面共享
  • cookie的数据始终在同源的http请求中携带(即使不需要),即cookie会自动传递到服务器;sessionStorage和localStorage数据保存在本地,不会自动把数据发给服务器;cookie数据有路径的概念,可以限制cookie只属于某个路径下