cookie 及其替代方案

2020/03/20 功能实现

本地有效期存储数据

记录 cookie 的概念,设置获取删除

http 里面协议是没有状态的,每一次 http 请求都是独立的无关的。 但是在 web 应用中,多个请求之间共享会话是非常必要的,所以 cookie 是为了辨别用户身份,进行会话跟踪而存储在 客户端上的数据。向同一个域名下发送请求,都会携带像他的 Cookie,服务器拿到它之后会进行解析,相当于拿到了客户端的状态

第一次客户端向服务器发送请求的时候,服务器就会通过响应头 Set-Cookie 向客户端种植 Cookie。以后客户端再向服务器发起请求的时候会带上 Cookie 服务器通过读取请求头中的 cookie 进行响应。但是这个有一点不安全,客户端可以修改 Cookie 的值,导致下次服务器读取到了错误客户端的 Cookie 的值,获取不到用户信息。为了防止 cookie 信息被修改,我们可以进行对 cookie 进行签名防止串改

设置 cookie : document.cookie=newCookie,一次只能只能对一个 cookie 进行操作,newCookie 后面的可选参数有 ;path='cookie的路径,只有路径匹配才能读到,只匹配前缀';domain='在哪一个域名下可以访问';max-age=max-age-in-seconds最大存活时间相对时间;expires=date-inGMTSting-format过期时间,绝对时间;httpOlony=true只能通过 HTTP 协议传输,不能通过 JS 访问,这也是预防 XSS 攻击的重要手段。;SameSite='Strict' 或者是自定义

SameSite 可以设置为三个值,StrictLaxNone 。 a. 在 Strict 模式下,浏览器完全禁止第三方请求携带 Cookie 。比如请求 sunseekers.cn 网站只能在 sunseekers.cn 域名当中请求才能携带 Cookie,在其他网站请求都不能。

b. 在 Lax 模式,就宽松一点了,但是只能在 get 方法提交表单况或者 a 标签发送 get 请求的情况下可以携带 Cookie,其他情况均不能。

c. 在 None 模式下,也就是默认模式,请求会自动携带上 Cookie

设置 cookie: 原理是根据文档要求直接赋值操作,注意了,一次只能设置一个 cookie,不能操作多个 cookie

function setCookie(name,value,exdays){
  const now = new Date()
  now.setTime(now.getTime()+(exdays*24*60*60*1000))
  const expires = `expires=${now.toUTCString}`//toUTCString() 方法可根据世界时 (UTC) 把 Date 对象转换为字符串,并返回结果。
  console.log(expires);// 如果没有设置过期时间,默认浏览器关闭的时候清除 cookie,
  document.cookie=`${name}=${value}; ${expires}`
}

读取 cookie: 原理是利用 cookie 存储的规则,进行字符串的切割获取

function getCookie(name){
  const cname = `${name}=`
  const cookie = document.cookie.split(';')
  for(let i=0;i<cookie.length;i++){
    let cookieVal = cookie[i]
    while(cookieVal.charAt(0)===' ') cookieVal = cookieVal.substring(1)
    if(cookieVal.indexOf(cname)!=-1) return cookieVal.substring(cname.length, cookieVal.length);
  }
  return ''
}

清除 cookie: 原理是利用一个已经过期的时间,自动清除 cookie

function clearCookie(name){
  setCookie(name,"",-1)
}

注意了:

chrome 浏览器在本地获取不到 cookie。必须在服务器上才可以。如果是本地的话,你可以放到 localwww 目录下面。

Google Chrome 只支持在线网站的 cookie 的读写操作,对本地 htmlcookie 操作是禁止的。所以下面的代码如果你写在一个本地的 html 文件中,将弹出的对话框内容为空。

如果我们设置了新的 cookie ,旧的 cookie 不会被覆盖,只是将新的添加到 document.cookie 中.

node 进行客户端种植 cookie ,实现原理很简单,就是在响应体里面加一个 Set-Cookie 字段就够了

const http = require('http')
const serve = http
  .createServer((req, res) => {
    if (req.url === '/write') {
      res.setHeader('Set-Cookie', 'name=sunseekers')
      res.end('write cookie ok')
    } else if (req.url === '/read') {
      let cookie = req.headers['cookie']
      res.end(cookie)
    } else {
      res.end('not found')
    }
  })
  .listen(8888)

可能被客户端篡改,使用前验证合法性,因为数据在客户端保存,服务器没有保存 不要存储敏感数据,比如用户密码,账户余额 使用 httpOnly 保证安全 尽量减少 cookie 的体积,限制了 64k 设置正确的 domainpath,减少数据传输 ,只有匹配上的时候才会发送到服务器

是一种记录客户端状态/数据的一种机智,只是他是保存在服务端的,客户端访问服务器的时候,服务器会以某一种形式记录在服务器上。这样比客户端会安全很多,浏览器无法修改,但是他会占用服务器的性能,如果数据量多的话

简单说就是,session 会生成一个唯一的表识符给客户端,服务端根据这个唯一的表识符存储数据。下次客户端通过请求头中的 cookie 把唯一的表识符发送给服务器,服务器根据这个唯一的表识符去读取数据

他的优点:比 cookie 更加安全,客户端不能够随意的修改

他的缺点:占用服务器内存,不同的服务器共享 session 不方便

session 的替代方案 JWT

JWT(json web token) 是在客户端和服务端通信的被认证的用户身份信息,便于获取在服务器上面的信息,不方便存储敏感信息

一旦用户完成了登陆,在接下来的每个请求中包含 JWT,可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。

信息交换在通信的双方之间使用 JWT 对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的

JWT 包含了使用.分隔的三部分:

Header 头部: { "alg": "HS256", "typ": "JWT"} ,使用 Base64Url 编码组成了 JWT 结构的第一部分

Payload 负载: 服务端要给我的信息,有效期等

Signature 签名:使用编码后的 headerpayload 以及一个秘钥(秘钥所以服务器共享且都是一样的,不能泄漏)

使用:

当用户使用它的认证信息登陆系统之后,服务器会返回给用户一个 JWT

用户只需要本地保存该 token(通常使用 local storage,也可以使用 cookie )即可

当用户希望访问一个受保护的路由或者资源的时候,通常应该在 Authorization 头部使用 Bearer 模式添加 JWT ,其内容看起来是下面这样

Authorization: Bearer <token>

因为用户的状态在服务端的内存中是不存储的,所以这是一种无状态的认证机制

服务端的保护路由将会检查请求头 Authorization 中的 JWT 信息,如果合法,则允许用户的行为。

由于 JWT 是自包含的,因此减少了需要查询数据库的需要

JWT 的这些特性使得我们可以完全依赖其无状态的特性提供数据 API 服务,甚至是创建一个下载流服务。 因为 JWT 并不使用 Cookie 的,所以你可以使用任何域名提供你的API服务而不需要担心跨域资源共享问题(CORS)

其实就是相当于在请求头加一个 Authorization 字段,服务器对 Authorization 字段做一次验证,检测是否有被修改过

参考资料

JS 设置 cookie,删除 cookie Document.cookie 浏览器系列之 Cookie 和 SameSite 属性


有时候,虽然素未谋面。却已相识很久,很微妙也很知足。在逝去的岁月里,我们在某一刻,共同经历着一样的情愫。

如果喜欢我的话,我们可以互相关注,相互学习的哟!互相鼓励,你的关注是我最大的动力来源

sunseekers

Search

    Table of Contents