Skip to content
快速预览

会话控制session、token、cookie

✍️ w 🕒 2023-06-15 06:21:46(a year ago) 🔗 F.开发中杂七杂八 session token cookie

HTTP 是一种无状态的协议,它没有办法区分多次的请求是否来自于同一个客户端, 无法区分用户,实际开发中我们需要知道实际访问用户,所以我们需要通过 会话控制 来解决该问题,简单的说 络通信时的身份验证和安全措施,确保双方进行安全可靠的数据传输和交互。在Web应用程序中,它保证用户在一段时间内可以保持登录状态,访问相关资源和功能,同时防止未经授权的侵入

常见的三种会话控制:

  1. Cookie:在客户端(通常是浏览器)中保存一些数据,并在后续的请求中自动发送给服务器。服务器可以通过读取Cookie的值来判断当前请求是否来自于同一个客户端。

  2. Session:在服务器端保存客户端的会话状态,通常是以某种数据结构(如Hash表)保存在内存或者数据库中。当客户端发起请求时,服务器可以通过获取session ID来获取客户端的会话状态,从而识别该请求是否来自于同一个会话。

  3. Token:在客户端和服务器之间传递的一种加密字符串,用于验证客户端的身份。客户端在登录成功后将获取到的Token保存起来,并在后续的请求中发送给服务器,服务器验证Token的有效性来判断当前请求是否来自于已经登录的客户端。Token通常使用JSON Web Token(JWT)来实现。

Cookie是一种在客户端保存会话状态的机制,类型为 小型文本文件,某些网站为了辨别用户身份而存储在用户本地终端(Client Side)上的数据cookie 是保存在浏览器端的一小块数据,cookie 是按照域名划分保存的

浏览器会在特定的情况下携带上 cookie 来发送请求,我们可以通过 cookie 来获取一些信息,使用Cookie,整个过程是服务器可以将一个唯一的标识符分配给客户端,并将其存储在浏览器中。客户端在随后的请求中将这个标识符传递回服务器,服务器可以以此标识客户端,并从先前存储的数据中确定客户端的身份和状态。

Cookie总是保存在客户端中,按在客户端中的存储位置,Cookie 可以分为 内存Cookie硬盘Cookie

  • 内存Cookie由浏览器维护,保存在内存中,浏览器关闭时Cookie就会消失,其存在时间是短暂的;
  • 硬盘Cookie保存在硬盘中,有一个过期时间,用户手动清理或者过期时间到时,才会被清理

一般判断cookie 是内存还是硬盘上

  • 没有设置过期时间,默认情况下cookie是内存cookie,在关闭浏览器时会自动删除;
  • 有设置过期时间,并且过期时间不为0或者负数的cookie,是硬盘cookie,需要手动或者到期时,才会删除

认情况下的cookie是内存cookie,也称之为会话cookie,也就是在浏览器关闭时会自动被删除,我们可以通过设置 expires 或者 max-age 来设置过期的时间使其可以成为储存在硬盘上

  • expires:设置的是Date.toUTCString(),设置格式是;expires=date-in-GMTString-format;
  • max-age:设置过期的秒钟,;max-age=max-age-in-seconds (例如一年为60* 60* 24*365);

在解释 cookie 作用域 之前需要了解关于域名,互联网中的地址其实是 IP 地址,有 IPV4 和 IPV6 两种类型,但 IP 地址比较难记忆,因此发明了有特殊含义的域名方便用户使用,域名和ip地址形成关联

域名的发明,使得用户可以通过记忆一个易于理解的名称来访问互联网上的各种资源,而不必记忆复杂的IP地址。同时,域名也方便了网站的管理和维护,使得网站可以更加灵活地调整服务器的配置和部署。

域名由两组或两组以上的字符组成,可以是ASCII字符或各国语言字符。各组字符之间用点号分隔开,最右边的字符组被称为顶级域名或一级域名,例如.com、.org、.net等。倒数第二组字符被称为二级域名,例如google.com中的google就是二级域名。倒数第三组字符被称为三级域名

顶级域名分为三类

  • 通用顶级域名(例如.com、.org、.net等)
  • 国家顶级域名(例如.cn、.uk、.jp等)
  • 新顶级域名是一种新的网站命名方式,它们比较新,有很多种,比如.xyz、.top、.red、.men等等。这些新的域名可以让网站的名字更加丰富多彩,更容易记忆,也更容易表达网站的主题和内容。

以 www.qq.com 为例子,www.qq.com 是三级域名。其中,com是顶级域名(一级域名),qq.com是二级域名,www.qq.com是三级域名。这里要说明用"www"子域名是因为它是一个较为常见的惯例。在网络的早期,人们将WWW视为"World Wide Web"的缩写,在域名系统中创建了一个子域名来代表Web服务器。它已经成为了互联网上网站的标准前缀,格式为"www.example.com",因此当用户输入网站时,他们经常会自动添加"www"前缀。此外,使用"www"子域名还可以将Web服务器与电子邮件服务器分离开来,并使网站负载平衡等配置变得更加容易。总之,虽然使用"www"子域名是一种惯例,但在某些情况下,不使用它也是完全可以的。因此这个案例中的 www 其实属于三级域名

图 2

也就是说实际上 www.baidu.com 和 baidu.com 是两个域名,每个域名都对应着一个唯一的IP地址,用于标识该域名所在的服务器。用户在浏览器中输入一个域名时,浏览器会向DNS服务器发送一个请求,请求DNS服务器将该域名解析为对应的IP地址。如果该域名对应的IP地址有多个,DNS服务器会返回其中一个IP地址,告诉浏览器将请求转发到该IP地址对应的服务器上。

因此,如果用户在浏览器中输入www.baidu.com,浏览器会向DNS服务器发送一个请求,请求DNS服务器将www.baidu.com解析为对应的IP地址,然后将请求转发到该IP地址对应的服务器上。如果用户在浏览器中输入baidu.com,浏览器会向DNS服务器发送一个请求,请求DNS服务器将baidu.com解析为对应的IP地址,然后将请求转发到该IP地址对应的服务器上。

但实际上经常发现网站访问 带www 前缀 和 不带前缀 都访问到同一个 是因为解析配置,如下图 @符号通常表示根域名或者当前域名。当你在DNS解析服务商的控制面板中添加一条记录时,如果将记录名设置为@,则表示该记录是针对当前域名的。例如,如果你的域名是example.com,那么@.example.com就表示针对example.com域名的记录,这个图将带 www 前缀的三级域名和不带前缀的二级域名都指向同一个 ip 地址因此 让二者访问都是一个服务器

图 3

来看一个 qq 的 new 三级域名 并没有 www

图 4

弄清了这些再来看 cookie 作用域

  1. 域级别 Cookie:域级别 Cookie 在特定的域名和子域名下都有效。cookie 是不可跨域的 每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain)。例如,如果您设置域名为example.com,则所有在 example.com 和其子域名下的页面都可以访问该 Cookie。也就是说 包括 "www.example.com"、"new.example.com"、"aaa.bbb.example.com" 等子域名下的页面。也就是说,这些子域名的访问者都可以访问该 Cookie。
  2. 路径级别 Cookie:路径级别 Cookie 只在特定路径下有效。例如,如果您将 Cookie 的路径设置为 /login,则该 Cookie 只在用户访问/login路径时发送给服务器。在设置 Cookie 时,可以使用 "Path" 属性来设置路径级别的 Cookie。在 HTTP 响应标头中设置 "Path" 属性值时,指定了该 Cookie 的路径。例如:Set-Cookie: cookie_name=cookie_value; Path=/login; 这将使得这个Cookie只在访问路径为 /login 的URL时被发送到服务器,如果在其他路径下如 /register 或 /home 下访问,浏览器就不会发送该 Cookie 到服务器。需要注意的是,设置路径级别 Cookie 需要保证所设置的路径存在,否则浏览器就不会发送该 Cookie 到服务器。另外,如果没有设置路径,默认情况下是 "/",即整个网站的路径都可以访问该 Cookie。
  3. 设置 SameSite 属性来设置同源级别。这个在下面会具体说,在浏览器中默认是lax

下面是 Cookie 可以设置的常用属性:

  1. name:Cookie 的名称
  2. value:Cookie 的值
  3. expires:Cookie 的过期日期(一般情况下是一个 GMT 格式的时间字符串)
  4. max-age:Cookie 的最长有效期,单位是秒
  5. domain:Cookie 的作用域,指定哪些主机可以访问 Cookie。它通常以点号开头,例如 .example.com 表示所有子域名都可以访问
  6. path:Cookie 的路径,指定哪些 URL 可以访问 Cookie
  7. Secure:Cookie 是否仅在使用 SSL/TLS 协议和 HTTPS 连接时发送到服务器端
  8. HttpOnly:Cookie 是否只能被 HTTP 请求访问,不能被 JavaScript 等脚本语言访问,以提高 Cookie 的安全性,如果给某个 cookie 设置了 httpOnly 属性,则无法通过 JS 脚本 读取到该 cookie 的信息,但还是能通过 Application 中手动修改 cookie,所以只是在一定程度上可以防止 XSS 攻击,不是绝对的安全
  9. sameSite:指定 cookie 的浏览器限制级别。sameSite 选项有三种可能值,分别是 strict, lax 和 none。同源级别设置更多可以参考csrf攻击章节
    • Strict 时,最为严格只有从主站点设置的请求才能够携带相应的 Cookie。也就是说,如果当前用户在主站点登录,并设置了一个带 Cookie 的会话,那么这个会话只能在访问主站点的请求中携带,所有其他的第三方请求都不能够携带该 Cookie。举个例子,假设当前用户在主站点 example.com 上登录,该站点设置了一个 Cookie,而在用户尝试访问子域名 blog.example.com 时,该请求就不能够携带来自 example.com 的 Cookie 或者 当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。
    • Lax 时,主站点设置的 Cookie 可以被从该站点链接的 GET 请求所带例如 连接 预加载 GET表单等,而对于受限的非 GET 请求通过 img、iframe 等标签加载的 URL,Cookie 则不会被携带例如在第三方站点中使用 Post 方法,这些场景都不会携带 Cookie。举个例子,假设当前用户在主站点 example.com 上登录,该站点设置了一个 Cookie,而在用户尝试访问子域名 blog.example.com 时,如果这是一个 GET 请求,那么它可以携带来自 example.com 的 Cookie,但其他类型的请求则不能够携带 Cookie。
    • None 时,任何请求都可以携带来自主站点设置的 Cookie,但是必须同时设置 Secure 属性,即 Secure 属性必须为 true。这意味着,Cookie 只能在 HTTPS 连接中使用,而不能在非 HTTPS 连接中使用。举个例子,假设当前用户在主站点 example.com 上登录,该站点设置了一个 Cookie,而在用户尝试通过一个 HTTPS 连接访问非主站点的网站或路径时,它就可以携带来自 example.com 的 Cookie,但在非 HTTPS 连接中则不能携带。

在浏览器客户端

在浏览器操作 cookie 可以通过 document.cookie, 设置cookie

js
document.cookie = "name=wcy"
document.cookie = "age=18"
document.cookie = "name=wcy;max-age=10" // 设置cookie,同时设置过期时间(默认单位是秒钟)

或者使用第三方 js-cookie 库

js
// 设置 Cookie
Cookies.set('cookie_name', 'cookie_value');

// 获取 Cookie
var cookie_value = Cookies.get('cookie_name');

// 删除 Cookie
Cookies.remove('cookie_name');

但实际上 让客户端设置 cookie 是危险的一般是禁止的防止跨站点脚本攻击(XSS)

服务端发起特点上

当服务器向客户端发送HTTP响应时,响应头部可以包含一个名为 Set-Cookie 的属性,该属性用于在客户端存储一个Cookie,包括一个名称/值对,可以选择性地包含其他属性,如过期时间、域名、路径、安全性等

shell
Set-Cookie: name=value; expires=Sun, 17-Jul-2022 01:00:00 GMT; path=/

浏览器向服务器发送请求时,会自动将 当前域名下 可用的 Cookie 设置在请求头中,然后传递给服务器

shell
Cookie: name=value

由于Cookie存储在客户端,因此客户端可以编辑、删除甚至伪造Cookie值。因此,Cookie通常用于存储不敏感的信息和身份验证令牌,而不是用于存储敏感信息。此外,使用Cookie时需要注意安全性和隐私问题,例如在浏览器中禁用Cookie,或者使用加密和签名等技术来保护Cookie数据。

想设置 cookie 不可编辑,可以将 cookie 的 HttpOnly 属性设置为 true。这个属性的作用是,让 cookie 不能被客户端 JavaScript 修改。这样可以防止跨站点脚本攻击(XSS)。nodejs 设置为例

js
res.setHeader('Set-Cookie', ['name=value; httpOnly'])

在浏览器查看cookie 图 1

整体流程图

图 6

综合

如果我们将用户信息保存在cookie 以明文的形式,容易被轻易一旦被劫持,全部信息都会泄露,并且客户端数据量变大,网络传输的数据量也会变大

Session

Session是基于cookie实现机制,因此Session 本质还是利用了 cookies ,不同点在于如果将cookies 的信息保存在后台中,将id 返回给前端,前端再将id 返回的时候进行反查就可以找到对应实际能容整个过程就是,当用户首次访问 Web 应用程序时,服务器会为该用户创建一个唯一的 Session,并生成一个与之关联的 Session ID。此 Session ID 通常会通过 Cookie 发送给客户端并存储在浏览器中。当用户再次访问应用程序时,浏览器会将 Session ID 发送回服务器,服务器根据 Session ID 查找对应的 Session,从而识别用户并获取其会话信息。

图 5

但要说明的是现在大多都是 cookie + sessionID 的方案,这种方案只是其中一种。虽然是最常用的,但并不是唯一的方法

  • URL 参数:将 session ID 作为 URL 的参数传递,这种方式的优点是简单易用,但是缺点是 URL 中会暴露 session ID,存在安全风险。www.example.com?session="12121212"
  • 隐藏表单域:将 session ID 作为隐藏表单域的值传递,这种方式的优点是相对安全,但是缺点是需要在页面中添加隐藏表单域,增加了页面的复杂度。
  • HTTP 头信息:将 session ID 作为 HTTP 头信息的一部分传递,这种方式的优点是相对安全,但是缺点是需要在客户端和服务器端都进行特殊处理

sessionID在客户端但是对应的 Session内容在服务端存储方式:Session 信息通常存储在服务器的内存中,但也可以存储在数据库、缓存服务器(如 Redis)或其他持久化存储中,以实现 Session 的共享和持久化。注意如果放在内存中,一旦服务器宕机,所有用户都要重新登录

生命周期:Session 通常具有固定的过期时间,例如 30 分钟。当用户在过期时间内没有任何活动(如发送请求)时,服务器会自动销毁该 Session,以释放资源。用户可以通过登录或其他操作来刷新 Session 的过期时间

安全性:由于 Session 依赖于 Cookie,可能受到 CSRF(跨站请求伪造)攻击。为了提高安全性,可以使用一些安全措施预防,如设置 HttpOnly 属性以防止 JavaScript 访问 Cookie,使用安全的 Cookie(Secure Cookie)以确保仅通过 HTTPS 传输,以及使用 CSRF 令牌等。

因此综合来看优缺点:Session 的优点是实现简单,易于管理,且可以存储较大量的用户会话信息。缺点是占用服务器资源当大量的session 信息需要保存在数据库或者内存中,可能影响服务器的性能和可扩展性;依赖于 Cookie,可能受到 CSRF 攻击;不适合跨平台和跨域的应用场景。

sessionId 会映射到 在服务端储存会话信息的内存数据或者是表中的数据,这种形式成为有状态的管理,因为 状态 或 会话 保存在 DB 或者内存中,和下面的jwt 无状态的形成对比

  1. 存在的位置 cookie:浏览器端 session:服务端
  2. 安全性 cookie 是以明文key value 形式,当然也可以通过加密解密的方式存放在客户端的,安全性相对较低 ,session 存放于服务器中,所以安全性 相对 较好
  3. 网络传输量 cookie 设置内容过多会增大报文体积, 会影响传输效率,session 数据存储在服务器,只是通过 cookie 传递 id,所以不影响传输效率
  4. 存储限制浏览器限制单个 cookie 保存的数据不能超过 4K ,且单个域名下的存储数量也有限制, session 数据存储在服务器中,所以没有这些限制
  5. Cookie会被附加在每个HTTP请求中,所以无形中增加了流量(事实上某些请求是不需要的)例如img 标签
  6. 有些浏览器禁掉了 cookie 将会失效的
  7. cookie 容易受到CSRF 攻击。
  8. 如果是处理对于分布式系统和服务器集群 的应用 session 将会变得麻烦 参考微服务下的分布式session管理 参考互联网分布式系统Session一致性问题解析参考三分布式 session 的4个解决方案参考分布式架构下 session 共享方案 能解决但是比较麻烦

图 10

cookie 诞生初似乎是用于电商存放用户购物车一类的数据,但现在前端拥有两个 storage(local、session),两种数据库(websql、IndexedDB),根本不愁信息存放问题,那是否保存浏览器其他位置就是安全的,在计算机中只有相对安全没有绝对安全对比一下在 Cookies (Storage) vs Web Storage

存储方式LOCAL/SESSION STORAGE 本地/会话存储COOKIES (STORAGE) 饼干(贮存)
JavaScript可通过同一域上的 JavaScript 访问Cookies 与 HttpOnly Cookie 标志一起使用时,不能通过 JavaScript 访问
XSS 攻击容易受到 XSS 攻击对 XSS 免疫(使用 HttpOnly 标志)
CSRF 攻击对 CSRF 攻击免疫易受 CSRF 攻击
缓解措施不要在此储存私有/敏感/认证相关的资料使用 CSRF 令牌或其他预防方法,同时使用 HttpOnly 标志与 Cookies

注:XSS 是一种漏洞,攻击者在其中注入将在您的页面上运行的 JavaScript,基本的 XSS 攻击尝试通过表单输入注入 JavaScript,通过运行脚本获取信息

关于token

最初演变过程是将 个人信息保存在保存在 cookie 中,因为内容信息都在客户端并且明文不安全容易被篡改,后来利用了session 的形式,但需要在后台进行保存,如果遇到了分布式需要额外重新设置,最重要的是如果用户禁用 Cookie 后,系统就无法正常使用了。

如果我们在在验证了用户账号和密码正确的情况,给用户颁发一个令牌(token) ,这个令牌作为后续用户访问一些接口或者资源的凭证,可以根据这个凭证来判断用户是否有权限来访问整个过程是

  • 生成token:登录的时候,颁发token;
  • 验证token:访问某些资源或者接口时,验证token;

Token可以使用多种技术来实现,以下是一些常见的实现方式: 以下是不同Token实现方式的优缺点对比表:

Token实现方式优点缺点
JSON Web Token (JWT)- 可以在客户端和服务器之间安全地传输信息
- 载荷可以包含用户信息和其他元数据
- 签名可以验证令牌的完整性和真实性
- 令牌可能会被篡改或伪造
- 载荷中的信息可能会被暴露
- 令牌过期后需要重新生成
OAuth 2.0- 可以授权第三方应用程序访问受保护的资源
- 可以使用刷新令牌来更新访问令牌
- 可以限制令牌的范围和有效期
- 令牌可能会被盗用或泄露
- 令牌的授权范围可能会被滥用
- 令牌的有效期可能会过长或过短
OpenID Connect- 可以安全地传输用户身份信息
- 可以使用访问令牌来访问受保护的资源
- 可以使用ID令牌来验证用户身份
- 令牌可能会被篡改或伪造
- 令牌的有效期可能会过长或过短
- 令牌的验证可能会受到中间人攻击的影响
SAML- 可以在不同的安全域之间安全地传输身份信息
- 可以使用断言令牌来访问受保护的资源
- 可以使用身份令牌来验证用户身份
- 令牌可能会被篡改或伪造
- 令牌的验证可能会受到中间人攻击的影响
- 令牌的生成和验证可能会比较复杂
Kerberos- 可以在客户端和服务器之间安全地传输身份信息
- 可以使用服务票据来访问受保护的资源
- 可以使用票据授予票据来验证用户身份
- 令牌可能会被篡改或伪造
- 令牌的验证可能会受到中间人攻击的影响
- 令牌的生成和验证可能会比较复杂

token -- jwt 方案

JSON Web Token(简称 JWT)是目前最流行的**跨域(cookie 是不能跨域的)**认证解决方案。 它是一种基于 Token 的身份认证机制,它的特点是无状态,也就是说,它不需要在服务端保存会话信息,也不需要在客户端保存会话状态,JWT 令牌有时被称为 Bearer Tokens ,因为关于用户的所有信息(即 Bearer)都包含在令牌中

JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

json
{
  "姓名": "张三",
  "角色": "管理员",
  "到期时间": "2018年7月1日0点0分"
}

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名,服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了

JWT生成的Token由三部分组成 header(头部)、payload(载荷)和 signature(签名),它是一个很长的字符串,中间用点(.)分割,JWT 内部是没有换行的 总体的简写表现形式 Header.Payload.SignatureJWT 不是通过任何方式加密的,而是用 Base64URL编码的。下面内容一定注意这一点

Base64URL

Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+/=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-/替换成_ 。这就是 Base64URL 算法。

图 7

header 会通过base64Url算法进行编码;

  • alg:采用的加密算法,默认是 HMAC SHA256(HS256),采用同一个密钥进行加密和解密;
  • typ:JWT,固定值,通常都写成JWT即可;
json
{
  "alg": "HS256",
  "typ": "JWT"
}

Payload,部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。会通过 base64Url 算法进行编码,注意JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号 除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。
json
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Signature部分是对前两部分的签名,防止数据篡改,首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),通过将前两个的结果合并后进行HMACSHA256的算法

shell
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

这样最后生成的 JWT 在没有得到 secret 情况下,虽然 header 和 payload 是 Base64URL编码可以解开明文看到,但是即使修改后 没有secret 也是不能反推会服务器认识的jwt,在 JWT 中,消息体是透明的,使用签名可以保证消息不被篡改。但不能实现数据加密功能,所以如果secretKey暴露是一件非常危险的事情,因为之后就可以模拟颁发token,也可以解密token

加密要注意的

  • 绝不要以明文存储密码 因为Payload 部分是Base64URL 并不是加密形式,因此重要信息例如密码可以进行加密后放入 Payload 比较好 因此 哈希算法 来处理密码,绝不要使用 Base64 或其他编码方式来存储密码,这和以明文存储密码是一样的,使用哈希,而不要使用编码。编码以及加密,都是双向的过程,而密码是保密的,应该只被它的所有者知道, 这个过程必须是单向的。哈希正是用于做这个的,从来没有解哈希这种说法, 但是编码就存在解码,加密就存在解密。
  • 绝不要使用弱哈希或已被破解的哈希算法,像 MD5 或 SHA1 ,只使用强密码哈希算法。
  • 绝不要以明文形式显示或发送密码,即使是对密码的所有者也应该这样。如果你需要 “忘记密码” 的功能,可以随机生成一个新的 一次性的(这点很重要)密码,然后把这个密码发送给用户。

jwt 生成

有两个在线网站 可以查看jwt,网站1 / 网站2

  • 我们通过网站可以看出来只能解开 header 和 payload 部分

图 8

JWT 的使用方式

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息 Authorization 字段里面。另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。

当用户希望访问一个受保护的路由或者资源的时候,需要请求头的 Authorization 字段中使用Bearer 模式添加 JWT,其内容看起来是下面这样,这种模式HTTP authentication 是一种标准化的校验方式,不会使用 cookie 和 session 相关技术。请求头带有 Authorization: Basic <credentials> 格式的授权字段。

shell
GET /calendar/v1/events
Host: api.example.com
Authorization: Bearer <token>

图 9

图 11

JWT 失效退出登录

和session cookie 相比他们都是可以通过设置过期时间来做到让验证失效,但注意 和 session 这种有状态相比,在用户退出后我们可以将 sessionID 数据从保存的位置踢出去,但 jwt 是无状态的即使是 退出了登录,但实际jwt 只要没过期还是依旧可以使用(因为jwt 的信息是在客户端,服务端只要解析后符合就能使用,并不关心其他)尤其是如果用户的 token 被泄露了,那么攻击者就可以在 token 过期前,不断的使用这个 token,这样就会造成安全问题。想要解决 就需要违背这种无状态规则

解决:jwt 模式的退出登录实际上是假的登录失效,因为只是浏览器端清除 token 形成的假象,假如用之前的 token 只要没过期仍然能够登陆成功

服务端白名单机制 白名单机制就是维护一个有效的 token 列表,当用户登录时,服务端会把生成的 token 存在服务端的内存中。在用户注销时,服务端会把这个 token 从内存中删除,这样,当用户再次请求时,服务端就会拒绝这个 token。这种方式和 cookie、session 的机制很像,但同样会带来内存上的开销。

服务端黑名单机制 黑名单机制和白名单机制相反,它维护一个无效的 token 列表,在用户注销登录后,会把用户 token 存到 token 列表中,当这个 token 再次被用来请求时,就会命中黑名单,而被拒绝请求黑名单机制不需要将所有登录的 JWT 都缓存,只在退出时缓存,有效的缓解了服务器的压力。黑名单机制非常巧妙的解决了内存消耗的问题,在实际场景中,token 过期的数量远远大于注销登录的数量,所以黑名单机制的内存消耗要远远小于白名单机制。

使用 JTI(JWT ID) 在 JWT 中添加一个唯一的标识符,当需要撤销某个 token 时,将该标识符加入黑名单中,这样就可以精确地撤销某个 token,而不是所有的 token。JTI(JWT ID)是 JWT 的一个标准字段,用于标识一个 JWT 的唯一性。每个 JWT 都应该有一个唯一的 JTI 值,这个值可以是一个 UUID,也可以是一个自定义的字符串。JTI 的作用是在撤销 JWT 时,可以精确地撤销某个 token,而不是所有的 token。当需要撤销某个 token 时,服务器可以将该 token 的 JTI 值加入黑名单中,这样就可以精确地撤销该 token。需要注意的是,JTI 值应该是随机生成的,并且应该保证唯一性。如果使用自定义的字符串作为 JTI 值,应该确保该字符串在所有 JWT 中都是唯一的。否则,可能会出现撤销某个 token 时,误撤销其他 token 的情况。

JTI 是将更加具体的id 保存在了黑名单数据库,相比将整个jwt 保存在黑名单里更加简洁占用字符更少,注意白名单是有点类似session的做法,单黑名单和 session 的做法并不等同,在保存量上更少只是关心退出的值进行保存

JWT 的几个特点

注意和 session 相比,jwt 将用户信息放到 Payload ,减少了不用去 数据库或者内存中 通过sessionID 获取session 信息在将session 中的信息获取后,例如获取用户id 在通过用户id 获取一些用户信息。而jwt 的Payload 直接包含用户 id 直接查询,中间少了一步在session 表中查找的一步。也不用在将信息 单独保存在session 表中而是将这部分信息直接保存在客户端

  1. JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
  2. JWT 不加密的情况下,不能将秘密数据写入 JWT(例如用户密码)。
  3. JWT 不仅可以用于认证,也可以用于交换信息。服务器保持了无状态特性,不需要将用户信息存在服务器或 Session 中,有效使用 JWT,可以降低服务器查询数据库的次数。
  4. JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
  5. JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
  6. 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
  7. 加密生成的数据比较长,相对来说占用了更大的流量
  8. 不依赖 Cookie,可跨端跨程序应用,支持移动设备(在安卓和ios 应用原生开发使用cookie 不方便的)

jwt 的无感刷新

https://blog.csdn.net/qq_34626094/article/details/131141865 ????

https://juejin.cn/post/7023253083475935240#heading-7 ???

解决单点token 泄露问题

jwt 包选择

更多语言包

OAuth2.0

https://ssshooter.com/2021-02-21-auth/#jwt ???

参考

一文读懂域名注册

顶级域名、二级域名、子域名是什么意思?

【图】3分钟弄明白顶级域名|二级域名|子域名|父域名的区别

MDN HTTP Cookie

会话 Cookie 与 JWT (JSON Web 令牌)之间的差异,用于会话管理

all-to-know-about-auth-and-cookies

基于 JWT 的身份认证

傻傻分不清之 Cookie、Session、Token、JWT

JSON Web Tokens

【Web第三篇】重新认识cookie与session

Node鉴权系列2:Express.js中使用session

关于鉴权,看懂这篇就够了

Released under the MIT License.