Web身份认证与状态管理:Cookie、Session 与 JWT

引言

在 Web 开发中,Cookie 、Session 和 JWT 是三种常见的身份认证和状态管理方式。它们在用户身份验证、会话管理以及跨域访问等方面扮演着重要角色。然而,不同的机制有不同的特点、适用场景和安全风险。

一、认证、授权和凭证

1.1 认证的定义

  • 简单来说,认证就是确认用户的真实身份,确保"你就是你"。

  • 在网络环境中,认证通常通过以下几种方式实现:

    • 使用用户名和密码登录
    • 通过邮箱发送登录链接
    • 通过手机接收验证码
    • 只要能接收到邮箱或验证码,系统就默认你是账户的合法拥有者

1.2 授权的定义

  • 授权是指用户允许第三方应用访问其特定资源的权限

    • 例如,在安装手机应用时,应用会请求访问相册、地理位置等权限
    • 在登录微信小程序时,小程序会请求获取昵称、头像、地区、性别等个人信息
  • 常见的授权实现方式包括:cookie、session和token

1.3 凭证的定义

  • 凭证是实现认证和授权的基础 ,它是一种身份标识(证书),用于标记访问者的身份。

二、什么是Cookie、Session和JWT

  • 定义:Cookie是服务器发送到用户浏览器并保存在本地的一小块数据。
  • 作用 :
    • 用于在客户端存储用户的会话信息或状态。
    • 每次浏览器向服务器发送请求时,会自动携带Cookie,从而实现身份验证或状态保持。
  • 特点 :
    • 存储在客户端(浏览器)。
    • 有大小限制(通常为4KB)。
    • 可以设置过期时间,分为会话Cookie(关闭浏览器后失效)和持久Cookie(根据过期时间失效)。
  • 应用场景 :
    • 保存用户登录状态。
    • 记录用户的偏好设置(如语言、主题)。

2.2 Session

  • 定义:Session是服务器端存储用户会话信息的一种机制。
  • 作用 :
    • 用于在服务器端保存用户的会话数据,通常与Cookie配合使用。
    • 服务器会为每个用户创建一个唯一的Session ID,并通过Cookie传递给客户端。
  • 特点 :
    • 存储在服务器端,安全性较高。
    • 依赖于Cookie来传递Session ID。
    • 会话结束后(如用户关闭浏览器),Session数据可能会被清除(取决于服务器配置)。
  • 应用场景 :
    • 保存用户的登录状态。
    • 存储用户的临时数据(如购物车信息)。

2.3 JWT(JSON Web Token)

  • 定义:JWT是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为JSON对象。
  • 作用 :
    • 用于在客户端和服务器之间传递认证信息或声明。
    • 通常用于无状态的分布式系统中。
  • 结构 :
    • Header:包含令牌类型和签名算法(如HMAC SHA256)。
    • Payload:包含声明(如用户ID、角色、过期时间等)。
    • Signature:用于验证令牌的完整性和真实性。
  • 特点 :
    • 存储在客户端(如LocalStorage或Cookie)。
    • 自包含性:所有信息都存储在令牌中,无需额外查询数据库。
    • 无状态性:服务器无需保存会话信息,适合分布式系统。
  • 应用场景 :
    • 用户认证与授权。
    • 跨域身份验证(如单点登录SSO)。
    • API接口的安全验证。

三、它们是如何维持用户登录状态的

  • 流程

前端发起登录请求,将用户名密码传给服务端,服务端在数据库查询进行用户名密码的认证,如果认证成功,会响应用户名到前端,前端把用户名保存到cookie,cookie保存在浏览器这一端,登录成功之后的所有请求都会自动带上这个cookie,这样就维持了用户的登录状态。

3.2 Session

  • 流程

前端发起登录请求,将用户名密码传给服务端,服务端在数据库查询进行用户名密码的认证,如果认证成功,就可以往session当中存入当前的用户信息,然后进行响应,会在响应头里存入一个set-cookie的属性,然后再把当前session的唯一ID放在属性当中,前端会自动在cookie当中存入当前的session ID,登录成功之后,下一次的请求就会自动在请求头当中设置cookie的信息,服务端拿到cookie中的session ID就可以得到这一次的请求所对应的session信息了,那么就可以获取到当前登录的用户信息,以维持当前登录状态。

3.3 JWT

  • 流程

前端发起登录请求,将用户名密码传给服务端,服务端在数据库查询进行用户名密码的认证,如果认证成功,服务端会生成一个JWT token(包含一些用户的基本非敏感信息,用户ID和用户名等)并返回给前端,前端保存这个token,在后续请求接口时在header中添加Authorization字段,并且把token放在该字段的value中,服务端通过header获取token之后,校验token的签名是否有效,若有效且token没有过期,则通过payload获取用户信息,以维持当前登录状态。

JWT 的原理

JWT(JSON Web Token)是一种紧凑且自包含的令牌格式,通常用于在客户端和服务器之间安全地传递信息。它的结构分为三部分,格式为:xxx.xxx.xxx,分别对应Header 、Payload 和Signature。

1. Header(头部)
  • 内容 :
    • alg:签名算法,例如HS256(HMAC SHA-256)。
    • typ:令牌类型,固定为JWT。
  • 特点 :
    • 经过Base64编码,公开可见。
    • 用于描述令牌的元数据和签名算法。

示例:

json 复制代码
{
  "alg": "HS256",
  "typ": "JWT"
}

2. Payload(荷载)
  • 内容 :
    • 包含用户的声明(claims),例如:
      • sub:用户ID(subject)。
      • name:用户名。
      • exp:过期时间(expiration time)。
      • 其他自定义字段(如角色、权限等)。
  • 特点 :
    • 经过Base64编码,公开可见。
    • 存储非敏感数据,因为可以被解码查看。

示例:

json 复制代码
{
  "sub": "1234567890",
  "name": "John Doe",
  "exp": 1516239022
}

3. Signature(签名)
  • 生成方式 :
    1. 将Header和Payload分别进行Base64编码,得到两个字符串。
    2. 将这两个字符串用.拼接起来,形成base64UrlEncode(Header) + "." + base64UrlEncode(Payload)。
    3. 使用Header中指定的签名算法(如HS256)和密钥(secret_key)对拼接后的字符串进行签名,生成签名部分。
  • 作用 :
    • 用于验证令牌的完整性和真实性,防止数据被篡改。

签名公式:

scss 复制代码
Signature = HMACSHA256(
  base64UrlEncode(Header) + "." + base64UrlEncode(Payload),
  secret_key
)

4. JWT 的验证过程
  1. 拆分Token :
    • 将JWT按.拆分为三部分:Header、Payload和Signature。
  2. 解码Header和Payload :
    • 对Header和Payload进行Base64解码,获取原始数据。
  3. 重新生成签名 :
    • 使用相同的密钥(secret_key)和签名算法,对解码后的Header和Payload重新生成签名。
  4. 比对签名 :
    • 将重新生成的签名与JWT中的Signature部分进行比对。
    • 如果一致,说明Token未被篡改,Payload中的数据可信。
    • 如果不一致,说明Token可能被篡改,验证失败。
5. JWT 的特点
  • 优点 :
    • 自包含:所有信息都存储在Token中,无需额外查询数据库。
    • 无状态:服务端无需保存会话信息,适合分布式系统。
    • 安全性:通过签名防止数据被篡改。
  • 缺点 :
    • Token一旦签发,在有效期内无法直接失效(需借助黑名单等机制)。
    • 如果未使用HTTPS,Token可能被窃取。

四、cookie、session和jwt的区别

4.1 存储位置

  • Cookie:数据存储在客户端(浏览器),每次请求时都会自动携带到服务器。
  • Session :数据存储在服务器,客户端通过 sessionId 访问服务器上的数据。
  • JWT :数据存储在客户端(一般保存在 localStorage、sessionStorage 或 cookie),服务器只负责验证,不存储用户状态。

4.2 安全性

  • Cookie:

    • 如果未设置 HttpOnly,JavaScript 可以访问,容易受到 XSS(跨站脚本攻击)。
    • 如果未设置 Secure,在 HTTP 连接中可能被劫持(中间人攻击)。
  • Session:

    • 服务器存储 Session 数据,较 Cookie 更安全。
    • 需要 Session 机制配合 cookie 或 token 进行身份识别。
  • JWT:

    • 采用签名(HMAC 或 RSA)保证数据完整性,但不能防止被窃取。
    • 一旦被拦截,由于 JWT 本身包含所有信息,可能导致更严重的数据泄露问题。

4.3 数据存储

  • Cookie:一般存储少量数据(4KB 限制)。
  • Session:存储在服务器,理论上可以存储大量数据,但会占用服务器资源。
  • JWT :存储在客户端,大小一般受限于 localStorage 或 cookie,但通常比 Cookie 能存储更多信息。

4.4 适用场景

  • Cookie:

    • 适用于存储少量的、对安全性要求不高的数据,如用户偏好设置。
    • 可用于轻量级的身份认证(如 remember me 功能)。
  • Session:

    • 适用于需要服务器存储用户信息的场景,如购物车、用户登录状态管理。
    • 适用于需要更高安全性的应用。
  • JWT:

    • 适用于无状态认证(Stateless Authentication),如单点登录(SSO)。
    • 适用于微服务架构,因为不需要服务器存储用户状态信息。

4.5 是否支持跨域

  • Cookie :默认不支持跨域访问,但可以通过 SameSite=None 和 CORS 配置来实现跨域。
  • Session:依赖 Cookie 机制,默认不能跨域。
  • JWT:可以在多个服务器或前后端分离的架构中使用,前提是正确配置 CORS。

4.6 是否支持无状态

  • Cookie:有状态(由服务器验证)。
  • Session:有状态(需要服务器存储)。
  • JWT:无状态(无需服务器存储,只需要验证签名)。

4.7 优缺点对比

特性 Cookie Session JWT
存储位置 客户端 服务器 客户端
安全性 较低 较高 取决于存储方式
服务器压力 无 高 无
适用场景 轻量级存储 需要存储用户状态 无状态认证、微服务
是否支持跨域 受限 受限 支持
是否可篡改 易被篡改 不易篡改 签名验证防篡改
适合单点登录(SSO) 否 否 是

五、注意事项

  1. 安全配置

    • 设置 HttpOnly,防止 JavaScript 访问,避免 XSS 攻击。

    • 设置 Secure,确保 Cookie 仅在 HTTPS 连接下传输,防止中间人攻击。

    • 使用 SameSite 限制 Cookie 发送行为,防止 CSRF 攻击:

      • Strict:不允许跨站请求携带 Cookie(最安全)。
      • Lax(默认):允许部分跨站请求(如 GET)。
      • None(需要 Secure):允许所有跨站请求,适用于跨域场景。
  2. 存储敏感信息

    • 避免存储用户密码等敏感信息,建议只存储 token 或 sessionId。
    • 若存储 JWT,建议设置较短的 httpOnly 失效时间,并配合 refresh token。
  3. Cookie 大小限制

    • 单个 Cookie 最大 4KB,存储过多数据会导致请求变大,影响性能。
  4. Cookie 过期时间

    • 使用 Expires 或 Max-Age 控制过期时间:

      • Session Cookie(不设置过期时间):浏览器关闭时删除。
      • Persistent Cookie(设置 Max-Age):可持久化存储。
  5. 跨域问题

    • 通过 Access-Control-Allow-Credentials: true 允许跨域携带 Cookie,但要确保 CORS 服务器正确配置。

5.2 使用 Session 时需要注意

  1. 存储方式

    • 默认存储在服务器内存中,适用于小规模应用,但大规模应用建议使用 Redis 或 数据库 存储,提高扩展性。
    • 如果 Session 过多,会占用服务器资源,影响性能。
  2. Session ID 传输

    • 通常通过 Cookie 传递 sessionId,但也可以通过 URL 传递(不推荐,容易被劫持)。
    • 使用 Secure 和 HttpOnly 保护存储 sessionId 的 Cookie,防止 XSS 和劫持攻击。
  3. Session 过期策略

    • 设定合理的过期时间,避免长期占用服务器资源:

      • 短期会话:如 30 分钟内无操作自动销毁。
      • 长期登录 :可以存储 Remember Me 机制,让用户保持登录状态。
  4. 分布式应用

    • 在多服务器环境下,Session 需要做 共享存储,避免用户在不同服务器登录时丢失 Session。

    • 方案:

      • Redis/Memcached:将 Session 存储到缓存,提高查询效率。
      • 数据库:适用于持久化存储 Session,但查询性能不如缓存。
  5. Session 固定攻击(Session Fixation)

    • 避免用户在认证前后使用相同的 Session ID,建议:

      • 在登录成功后,重新生成 Session ID。
      • 结合 IP 地址、User-Agent 进行身份校验,防止 Session 被盗用。

5.3 使用 JWT 时需要注意

  1. 避免 JWT 过长

    • JWT 由 Header.Payload.Signature 组成,存储过多数据会导致请求体积变大,影响性能。
    • 建议只存储必要信息(如用户 ID、角色权限),避免存储敏感数据。
  2. Token 过期策略

    • JWT 一旦生成,服务器无法主动销毁(除非存储黑名单)。

    • 解决方案:

      • 短期 Token(Access Token) :设置较短过期时间(如 15~30 分钟)。
      • 长期 Token(Refresh Token) :存储在数据库,用于刷新 Access Token,降低频繁登录的用户体验问题。
  3. 存储位置

    • Cookie(推荐) :搭配 HttpOnly 和 Secure 提高安全性。
    • localStorage / sessionStorage(不推荐) :容易被 XSS 攻击获取,增加被盗风险。
  4. 避免 Token 泄露

    • 一旦 Token 被窃取,攻击者可随意使用,因此:

      • 使用 HTTPS 传输 Token,防止中间人攻击。
      • 不在 URL 传递 Token(容易被日志或浏览器缓存暴露)。
      • 可结合 指纹识别(如 IP 绑定、设备 ID) 限制 Token 使用范围。
  5. Token 失效处理

    • JWT 无法主动撤销,因此可以:

      • 黑名单机制:存储废弃 Token 列表,但需要占用服务器资源。
      • 数据库存储 Token:在用户登出时,使数据库中该 Token 失效。
  6. 签名算法选择

    • 避免使用对称加密(如 HS256),尽量使用 非对称加密(如 RS256) ,提高安全性:

      • HS256(HMAC) :密钥泄露后攻击者可伪造 Token。
      • RS256(RSA) :公钥验证,私钥签名,更安全。
  7. 防止重放攻击

    • 使用 jti(JWT ID) 或 nonce(唯一随机数)确保 Token 不能被重复使用。
    • 结合时间戳 iat 和 exp,拒绝过期或重复请求。

结语

无论是 Cookie 、Session 还是 JWT ,它们各有优劣,并没有绝对的"最佳方案",而是需要根据业务需求和安全策略做出合理选择。对于一般的 Web 应用,Session 适用于服务器端身份管理 ,JWT 更适合分布式和无状态认证 ,而 Cookie 则在存储少量信息时更为便捷 。在实际开发中,除了选择合适的方案,还需要注意安全性,避免常见攻击风险,如 XSS、CSRF、Session 盗用 和 Token 泄露,以确保应用的稳定性和数据安全。

相关推荐
鬼手点金7 小时前
nanoGPT/nanochat 能做出 DeepSeek/Qwen 这样的大模型吗?
服务器·前端·javascript·bug·openclaw
蛋蛋的就会顺顺的8 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
程序员Sunday8 小时前
TypeScript 的 any、unknown、never 有什么区别?
前端·面试·typescript
朱涛的自习室8 小时前
70 美金的 Beyond Compare,我让 Gemini 4 和 DeepSeek 造个开源免费版(Day 2)
android·前端·人工智能
小 黄 鸡9 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
码艺-Alimjan9 小时前
Tauri 源码备份 · 打包 & 解压 总结,源码收集之路
前端·javascript·vue.js
小马不起床9 小时前
零基础玩转 FastAPI_11:前端后台管理页面
前端·状态模式·fastapi
子非鱼a10 小时前
【文件上传】一个普普通通的edu16
前端
美狐美颜SDK开放平台10 小时前
直播APP如何实现美白滤镜功能?视频美颜SDK技术开发方案详解
前端·数据库·人工智能·音视频·美颜sdk·直播美颜sdk·视频美颜sdk
pride.li11 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉