JWT和Session
JWT和Session
JWT(JSON Web Tokens)和 Session 是两种常用的身份验证
和会话管理
机制,它们在应用场景、实现方式和特性上有着显著的差异。
JWT(JSON Web Tokens)
- 无状态验证:JWT 是一种无状态的验证机制,每个 Token 自包含所有必要的信息,不需要服务器端存储会话信息。
- 跨服务认证:适合于微服务架构和分布式系统,因为不需要中央存储或同步会话信息。
用户在一个服务(如认证服务)中登录,接收 JWT。当用户访问其他微服务时,这些服务可以独立验证 JWT 的有效性,而无需每次都与认证服务进行交互。
优势:减少了微服务之间的耦合,并且由于 JWT 的自包含性,每个服务都可以快速验证用户身份。
- 移动端
避免移动端访问cookies的不便
- 扩展性和灵活性:易于在多个系统之间共享,支持跨域认证。
第三方认证
JWT 可用于 OAuth2 认证流程,例如,作为第三方应用与 Google、Facebook 等服务间的认证令牌。
流程:用户通过第三方服务登录并授权,第三方服务返回 JWT。该 JWT 然后可用于用户在第三方服务以外验证其身份。
优势:为用户提供了一种安全的方式来登录和授权第三方应用,而无需共享密码。
单点登录(SSO) :JWT可以用于实现SSO,让用户一次登录就可以访问多个相关应用程序
API身份验证:JWT可以用于保护API端点,确保只有经过身份验证的用户可以访问受保护的资源。
信息交换:JWT可以用于安全地在不同组织之间交换信息,例如在OAuth2流程中交换访问令牌。
Session
- 有状态验证:Session 存储在服务器端,每个用户的会话信息保存在服务器上。
- 跨域问题:
不易处理跨域请求
,因为 Session 依赖于特定的域。
选择 JWT 还是 Session
- 单页应用(SPA)和微服务:由于其无状态性和跨域能力,JWT 更适合于单页应用和微服务架构。
- 传统的多页应用(MPA) :如果应用是传统的服务器渲染多页应用,且运行在单个域下,Session 可能是更好的选择。
- 安全性考虑:虽然 JWT 通过加密和签名提供安全保障,但它们通常存储在客户端,可能受到 XSS 攻击的威胁。而 Session ID 通常存储在 Cookie 中,可以设置为
HttpOnly
以减少 XSS 的风险。 - 可扩展性和灵活性:JWT 更容易扩展到大型、分布式的系统中,而 Session 更适合集中式的、规模较小的应用。
JWT和Session认证流程和优缺点
JWT 认证流程
- 用户登录:用户通过提供凭证(如用户名和密码)登录。
- 生成 JWT:服务器验证用户凭证,如果凭证有效,则生成包含用户信息和一些元数据的 JWT,并对其进行数字签名。
- 发送 JWT:服务器将 JWT 发送回客户端。
- 存储 JWT:客户端存储 JWT,通常是在 localStorage、sessionStorage 或 Cookie 中。
- 随请求发送 JWT:客户端在随后的请求中将 JWT 作为认证信息发送给服务器,通常是通过 HTTP 请求头(如
Authorization: Bearer <token>
)。 - 验证 JWT:服务器在每个请求中验证 JWT 的有效性(包括签名和过期时间)。
JWT 的优缺点
缺点:
- 存储和安全性:由于 JWT 存储在客户端,可能存在被窃取的风险,尤其是在 XSS 攻击中。
- 过期处理:JWT 一旦发出后,直到过期之前都有效,无法在服务器端立即使其失效。
Session 认证流程
- 用户登录:用户通过提供凭证登录。
- 生成 Session:服务器验证用户凭证,如果凭证有效,则在服务器端创建一个 Session,并生成一个唯一的 Session ID。
- 发送 Session ID:服务器将 Session ID 作为 Cookie 发送回客户端。
- 客户端存储 Session ID:客户端浏览器存储 Session ID,并在随后的每个请求中自动发送它。
- 服务器验证 Session ID:服务器接收请求时,查找匹配的 Session ID,并确定用户的身份。
Session 的优缺点
优点:
- 集中管理:Session 存储在服务器端,易于管理。
- 灵活性:可以随时修改或使 Session 失效。
- 安全性:Session ID 可以设置为
HttpOnly
,减少 XSS 的风险。
缺点:
- 可扩展性:随着用户数量增加,Session 可能增加服务器的存储负担。
- 依赖 Cookie:Session 通常依赖于 Cookie,这可能会受到跨域和 CSRF 攻击的影响。
总结来说,JWT 适用于需要高可扩展性和跨域支持的应用场景,而 Session 更适合需要集中会话管理的传统应用。正确选择依赖于应用的特定需求和安全考虑。
其他特征
安全性:
- JWT的payload使用的是base64编码的,因此在JWT中不能存储敏感数据。而session的信息是存在服务端的,相对来说更安全
性能:
- 经过编码之后JWT将非常长,cookie的限制大小一般是4k,cookie很可能放不下,所以JWT一般放在local storage里面。并且用户在系统中的每一次http请求都会把JWT携带在Header里面,HTTP请求的Header可能比Body还要大。
- 而sessionId只是很短的一个字符串,因此使用JWT的HTTP请求比使用session的开销大得多
一次性:
无状态是JWT的特点,但也导致了这个问题,JWT是一次性的。想修改里面的内容,就必须签发一个新的JWT
- 无法废弃 一旦签发一个JWT,在到期之前就会始终有效,无法中途废弃。若想废弃,一种常用的处理手段是结合redis
- 续签 如果使用JWT做会话管理,传统的cookie续签方案一般都是框架自带的,session有效期30分钟,30分钟内如果有访问,有效期被刷新至30分钟。
- 一样的道理,要改变JWT的有效时间,就要签发新的JWT。最简单的一种方式是每次请求刷新JWT,即每个HTTP请求都返回一个新的JWT。这个方法不仅暴力不优雅,而且每次请求都要做JWT的加密解密,会带来性能问题。另一种方法是在redis中单独为每个JWT设置过期时间,每次访问时刷新JWT的过期时间
选择JWT或session:
我投JWT一票,JWT有很多缺点,但是在分布式环境下不需要像session一样额外实现多机数据共享,虽然seesion的多机数据共享可以通过粘性session、session共享、session复制、持久化session、terracoa实现seesion复制等多种成熟的方案来解决这个问题。
但是JWT不需要额外的工作,使用JWT不香吗?且JWT一次性的缺点可以结合redis进行弥补。扬长补短,因此在实际项目中选择的是使用JWT来进行认证
Token、JWT、SSO、OAuth2.0
SSO (Single Sign-On)
- 定义:SSO 是一种认证服务,允许用户使用一套凭据(如用户名和密码)来访问多个应用或服务。
- 应用:常见于企业环境,允许员工使用公司的单一认证系统访问多个内部应用。
- 与Token/JWT的关系:在 SSO 流程中,一旦用户认证成功,系统通常会生成 Token(如 JWT)来代表用户的登录状态,并用于后续的访问控制。
OAuth2
- 定义:OAuth2 是一个授权框架,允许第三方应用获取有限的访问权限,通常用于访问用户在另一个应用中的数据。
- 流程:在 OAuth2 中,用户授权第三方应用访问其在服务提供商中的信息。服务提供商随后向第三方应用发放 Token,如访问令牌(Access Token)和刷新令牌(Refresh Token)。
- 与JWT的关系:OAuth2 流程中使用的访问令牌可以是任何形式的 Token,包括 JWT。JWT 用于携带授权信息,使得第三方应用能够以用户的名义安全地访问服务。
JWT 和 OAuth 的区别
- OAuth2是一种授权框架 ,JWT是一种认证协议。
- 无论使用哪种方式切记用HTTPS来保证数据的安全性。
- OAuth2用在使用第三方账号登录的情况(比如使用weibo,qq,github登录某个app),而JWT
单独使用时,多数情况
下是用在前后端分离,需要简单的对后台API进行保护时使用。
总结
- Token 是一个广义的术语,可以用于身份验证和授权。
- JWT 是 Token 的一种具体实现,适用于多种认证和授权场景,包括跨域和无状态环境。
- SSO 使用 Token(如 JWT)来实现单点登录,允许用户通过单一身份验证访问多个服务。
- OAuth2 是一个授权框架,其中使用 Token(如 JWT)来授权第三方应用访问用户资源。
Q&A
最佳实践
- Access Token有效期: 应设置较短的有效期,如几分钟到几小时。
- Refresh Token有效期: 通常比Access Token长,可以根据应用需求设置为几天到几周。
- 安全措施: 应实施安全措施,如限制Refresh Token的使用次数,监控异常行为,提供Token撤销机制等。
- 用户体验: 在客户端实现无缝的Token刷新机制,以提供流畅的用户体验。 综上,每次刷新操作创建一个新的Access Token是JWT的标准做法,这有助于保持应用的安全性和简化状态管理。
刷新操作的流程
- 客户端请求刷新: 当Access Token过期,客户端使用Refresh Token请求一个新的Access Token。
- 服务器验证Refresh Token: 服务器检查Refresh Token是否有效,比如是否过期,是否与请求者匹配等。
- 发放新的Access Token: 如果Refresh Token有效,服务器发放一个新的Access Token。这个新Token将有一个全新的有效期。
- 客户端使用新的Access Token: 客户端开始使用新的Access Token来进行后续请求。
为什么创建新的Access Token而不是续期
- 不可变性: JWTs是不可变的,一旦创建,其内容(包括有效期)就不能更改。要更新Token的有效期或其他信息,必须创建一个全新的Token。
- 安全性: 通过定期创建新的Access Token,可以减少旧Token被盗用的风险。如果一个Access Token被窃取,窃取者只能在该Token短暂的有效期内使用它。
- 状态无关: JWT是无状态的,服务器不需要存储Token信息。每个Token包含了所有验证所需的信息。创建新的Token而不是在服务器端跟踪和更新Token状态,保持了这种无状态的特性。