cookie 及其替代方案

2020/03/20 功能实现 共 6510 字,约 19 分钟

Cookie 是一种存储在用户计算机上的文本文件,它可以帮助网站识别用户并存储有关用户的信息

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

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

名称(name): 用于存储 cookie 数据的键值对中的键,该属性是必需的。

值(value): 存储在 cookie 中的值,该属性是必需的。

失效时间(expires): 定义 cookie 的生命周期。如果在 cookie 中设置了失效时间,则 cookie 将在该时间到期,并从客户端计算机中删除。如果没有设置失效时间,cookie 将在用户关闭浏览器时删除。

域名(domain): 定义 cookie 可用的域名,该属性指定具有相同域名的所有页面都可以访问 cookie,这样可以在多个子域中共享 cookie。默认情况下,cookie 仅在创建它的域名下可用。

路径(path): 定义 cookie 可用的 URL 路径。默认情况下,cookie 仅在创建它的页面路径下可用。

安全标志(secure): 如果存在安全标志,则表示 cookie 只能通过 SSL/TLS 连接访问,可以确保 cookie 数据的机密性,提高安全性。(只能在HTTPS安全连接下传输

HttpOnly标志(HttpOnly):如果设置了 HttpOnly 属性,即使有漏洞,JavaScript 也无法访问 cookie,这样可以更有效地保护用户隐私安全。

设置cookie的domain用来实现什么功能?

多个子域共享cookie

防止跨站点攻击(和 Session Fixation 攻击): 由于默认情况下,cookie 的 domain 为当前页面所属域名,因此可以通过劫持用户跳转到非法网站等方式获取用户的 cookie,实现跨站点攻击。通过将 cookie 的 domain 设置为合适的范围,可以实现 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 字段做一次验证,检测是否有被修改过

cookie:客户端存储数据的方案,保存登录状态/用户偏好等信息,服务器在响应中设置cookie,客户端在后续请求时将cookie值带入请求头中,从而实现身份认证和状态保持

session: 服务端保持状态的机制,常用于使用用户在多个页面间共享信息,实现身份认证和授权。在使用 Session 时,客户端第一次请求时服务器生成一个唯一的 Session ID,将其存储在 Cookie 中返回给客户端,客户端后续请求时将 Session ID 带入请求头中,服务器根据该 ID 查找对应的会话信息,从而实现身份认证和状态保持。

Token: 令牌是一种在客户端和服务器之间交换信息的机制,可以用于身份验证、数据访问控制等场景。常用的 Token 类型有 Access Token 和 Refresh Token,Access Token 用于验证用户身份和访问控制,Refresh Token 用于在 Access Token 过期后获取新的 Token,从而实现持久授权。

JWT: JSON Web Token 是一种安全可靠的令牌,常用于 Web 应用程序的身份验证和授权。JWT 是一段包含一系列声明的加密信息,可以包含用户身份、权限信息等,并使用加密算法对信息进行签名和验证,保证信息的完整性和安全性。JWT 最大的优势在于可跨平台使用,不依赖于任何特定的技术或语言。

如何标识用户已经登录

采用 cookie:当用户第一次登录时,服务器会为用户设置一个 cookie,此后每次请求都会携带这个 cookie。此方式简单、易实现,但存在一定的安全风险,因为 cookie 可以被其他人修改、窃取,从而模拟已登录的用户。

采用 session:和 cookie 类似,当用户第一次登录时,服务器为用户建立一个 session。该 session 的 ID 被存储在一个 cookie 中,并发送给客户端浏览器。这个 session 只有在这个 cookie 存在的情况下才会被使用,从而保证了安全性。

采用 token:在服务端生成一个 token,并返回给客户端,在后续的请求中,客户端在头部信息或 URL 中携带这个 token 进行请求,服务器端验证 token 的正确性以判断用户是否已经登录。此方式也比较安全,因为 token 可以设置时效,过期后需要重新登录获取新的 token。 在实际使用中,也可以将 cookie 和 session 结合起来使用,或使用 token+cookie。需要根据具体场景选择合适的方式来标识用户已经登录。

token已经过期的话,我想要刷新token如何实现

在 Token 过期时,客户端向服务端发送请求,并提供原 Token,请求刷新 Token。

服务端验证客户端的身份和原 Token 是否有效。

如果验证通过,服务器生成一份新的有效期比较长的 Token,返回给客户端,并在数据库中更新旧 Token 的状态为无效。

客户端收到新 Token,用于后续请求,同时保存 Token。 总的来说,刷新 Token 的方式和生成 Token 的方式类似,只不过需要额外的逻辑来处理 Token 过期的情况。需要注意的是,为了保证 Token 刷新时的安全性,需要对 Token 进行访问限制,比如限制同一 Token 的刷新次数、时间间隔等,以避免被恶意用户利用刷新接口进行攻击。

扩展知识 Html5中本地存储概念是什么与cookie有什么区别

localStorage和sessionStorage还有IndexedDB对象数据库。

localStorage和sessionStorage可以在浏览器中保存一些数据,这些数据可以被网站访问和使用,而不需要每次都从服务器重新获取。

IndexedDB它支持事务和索引,可以存储大量的结构化数据,即前端数据库

可以快速、简便地在浏览器中保存少量数据,不需要像Cookie一样将所有数据都发送给服务器;

对于需要频繁访问的数据,可以在本地缓存中存储,从而提高网站的性能和速度;

容量:cookie最大只能存储4KB的数据,而localStorage和sessionStorage可以存储5MB的数据;

有效期:cookie有过期时间,而localStorage和sessionStorage永久有效;

性能:cookie在每次请求时都会发送给服务器,增加了网络流量,而本地存储将数据存储在用户终端,不需要每次都从服务器获取,提高了网站的性能和速度;

安全性:Cookie会暴露在HTTP请求中,容易被劫持和盗用,而本地存储不会暴露在HTTP请求中,提高了数据的安全性;

localStorage和sessionStorage的区别

生命周期:localStorage和sessionStorage的存储周期不同。localStorage存储的数据将一直存在,除非用户明确删除,而sessionStorage存储的数据只在当前会话期间存在(窗口或标签页关闭时自动清除)。

作用域:localStorage和sessionStorage的作用域也不同。localStorage的作用域是整个域名,不同的窗口和标签页都可以共享相同的localStorage。而sessionStorage的作用域只是当前窗口或标签页,不同的窗口和标签页无法共享相同的sessionStorage。

数据存储大小:localStorage和sessionStorage能够存储的数据大小也有区别。localStorage可以存储的数据量比sessionStorage大得多,通常能存储5MB数据。而sessionStorage只能存储少量数据,通常为5MB或者更少。

参考资料

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


在技术的历史长河中,虽然我们素未谋面,却已相识已久,很微妙也很知足。互联网让世界变得更小,你我之间更近。

在逝去的青葱岁月中,虽然我们未曾相遇,却共同经历着一样的情愫。谁的青春不曾迷茫或焦虑亦是无奈,谁不曾年少过

在未来的日子里,让我们共享好的文章,共同学习进步。有不错的文章记得分享给我,我不会写好的文章,所以我只能做一个搬运工

我叫 sunseekers(张敏) ,千千万万个张敏与你同在,18年电子商务专业毕业,毕业后在前端搬砖

如果喜欢我的话,恰巧我也喜欢你的话,让我们手拉手,肩并肩共同前行,相互学习,互相鼓励

文档信息

Search

    Table of Contents