彻底搞懂 JWT
彻底搞懂 JWT

彻底搞懂 JWT

Created
May 12, 2024 04:09 PM
Tags

什么是 JWT ?

JWT 全称 JSON Web Token,是一种用于在网络应用之间安全传递信息的开发标准,它定义了一种紧凑且独立的方式,用于 将信息作为 JSON 对象 在各方之间安全地传输。
其中,信息是可以被验证并信任的,因为它是经过数字签名的,通常可以使用密钥(对应使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对 JWT 进行签名。
JWT一般用于身份验证和非敏感数据的传递,其设计目的是不需要服务器端存储状态,安全地传输非敏感信息给受信任的实体。
这里强调“非敏感数据”是因为常用的JWT传递的信息并没有被JWT加密,任何人截取到JWT后都能读取到其中的内容,JWT侧重通过签名保证信息的可信,但信息的加密需要自己完成。
 
 
 

什么是 JWT结构?

JWT 由三个部分组成,用 .  分隔,它们是:
  • Header
  • Payload
  • Signature
因此,JWT 通常以xxxxx.yyyyy.zzzzz的形式出现。

Header

Header 通常由两部分组成:令牌类型(即 JWT)和正在使用的签名算法(如 HMAC SHA256 或 RSA)。
{ "alg": "HS256", "typ": "JWT" }
然后将此 JSON 编码为 Base64Url,形成 JWT 的第一部分。

Payload

第二部分是 Payload,通常包含若干 claims,或者称声明,它们是关于实体(例如用户)和其他数据的陈述,通常分为:已注册、公共和私有声明。
  • 已注册声明:一组预定义的声明,这些声明不是必须的但推荐使用,提供一组有用的、可互操作的声明。其中一些是:iss(发行者)、exp(过期时间)、sub(主题)、aud(受众)等。
请注意,声明名称只有三个字符长,因为 JWT 旨在紧凑。
Registered claims: These are a set of predefined claims which are not mandatory but recommended, to provide a set of useful, interoperable claims. Some of them are: iss(issuer), exp(expiration time), sub(subject), aud(audience), and others.
Notice that the claim names are only three characters long as JWT is meant to be compact.
  • 公开声明:这些可以由使用 JWT 的人随意定义。但为了避免冲突,应在 IANA JSON Web 令牌注册表中定义它们,或将其定义为包含抗冲突命名空间的 URI。
Public claims: These can be defined at will by those using JWTs. But to avoid collisions they should be defined in the IANA JSON Web Token Registry or be defined as a URI that contains a collision resistant namespace.
  • 私人声明:这些是为在同意使用它们的各方之间共享信息而创建的自定义声明,既不是注册声明也不是公开声明。
Private claims: These are the custom claims created to share information between parties that agree on using them and are neither registered or public claims.
{ "sub": "1234567890", "name": "John Doe", "admin": true } // Payload 示例
请注意,信息虽然可以防止篡改,但任何人都可以读取。除非 JWT 已加密,否则不要将机密信息放在 JWT 的有效负载或标头元素中。
然后将此 JSON 编码为 Base64Url,形成 JWT 的第二部分。

Signature

要创建签名部分,必须获取编码后的 Header、Payload,Header中指定的算法,以及最重要的:secret,才能进行签名。
例如,如果要使用 HMAC SHA256 算法(HS256),将按以下方式创建签名:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
签名用于验证消息在此过程中未更改,并且,对于使用私钥签名的令牌,它还可以验证 JWT 的发送者是否是它所说的人。
 
最终输出是三个由.分隔的 Base64-URL 字符串,可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(如 SAML)相比更紧凑。
 
 
 

JWT 是如何工作的?

JWT 获取:在身份验证中,当用户使用其凭据成功登录时,将返回 JWT。由于 JWT 是凭据,因此必须非常小心以防止出现安全问题。通常令牌应该妥善保管,保留时间应该有限制,不应将敏感会话数据存储在浏览器存储中。
JWT 使用:每当用户想要访问受保护的路由或资源时,都应发送 JWT,通常在 Authorization 标头中使用 Bearer 架构。标头的内容应如下所示:
Authorization: Bearer <token>
在 Authorization 标头中发送,则跨域资源共享 (CORS) 不会成为问题,因为它不使用 cookie。
JWT 验证:在某些具体的情况下,如无状态授权机制,服务器中受保护的路由将检查 Authorization 标头中是否存在有效的 JWT,如果存在,则允许用户访问受保护的资源。如果 JWT 包含必要的数据,还能减少对某些操作的数据库进行查询的需要,尽管情况可能并非总是如此。
请注意,如果通过 HTTP 标头发送 JWT 令牌,则应尽量防止它们变得太大。某些服务器不接受超过 8 KB 的标头。如果尝试在 JWT 令牌中嵌入太多信息(例如包含所有用户权限),则可能需要替代解决方案,例如 Auth0 细粒度授权。
 
下图显示了如何获取 JWT 并用于访问 API 或资源:
notion image
  1. The application or client requests authorization to the authorization server. This is performed through one of the different authorization flows. For example, a typical OpenID Connect compliant web application will go through the /oauth/authorize endpoint using the authorization code flow.
  1. When the authorization is granted, the authorization server returns an access token to the application.
  1. The application uses the access token to access a protected resource (like an API).
请注意,使用签名令牌时,令牌中包含的所有信息都会公开给用户或其他方,即使他们无法更改它。这意味着您不应将机密信息放入令牌中。
 
 
 

JWT 基本应用

身份认证

这是最常见的应用,用户在通过一些方式登录成功后会得到服务端签发的 JTW,它本身保存了一些用户的基本信息(ID、权限等),后续的请求都要带上这些非敏感的基本信息,可供服务端免去查询数据库的步骤,因为经过签名验证,这些信息是可信的。
sequenceDiagram participant 浏览器 participant 服务器 浏览器->>服务器: [1]Post /users/login 包含用户名密码 服务器->>服务器: [2]登陆成功 用 secret 生成 JWT Note over 服务器 : 签名的加密方式:<br/>对称加密、非对称加密 服务器->>浏览器: [3]返回 JWT 浏览器->>服务器: [4]后续的请求头包含 JWT 服务器->>服务器: [5]验证 JWT 签名,并从中获取用户信息 服务器->>浏览器: [6]验证通过,返回请求内容

TODO 扩展单点登录

 

密码重置电子邮件验证

用户请求重置密码时,请求用已绑定的电子邮件地址进行验证,服务器会生成包含用户信息的 JWT 并组成一个链接发往用户的邮箱,用户点击链接后就可以重置密码或完成电子邮件验证。
 
 
 

与其他认证机制的对比及缺点

除了 JWT,常用的还有基于 Cookie、 API Key 的认证机制
JWT
Cookie
API Key
是否有状态
有,可包含用户基本信息
无,只是用户标识
无,只是用户标识
应用场景
前后端之间、后端之间
前后端之间
一般用在后端之间
认证对象
主要针对用户
针对用户
主要针对系统、应用
可撤销(revoke)
不方便
方便
方便
生产方式
认证过程中动态生成
认证过程中动态生成
一般预先分配
由于 JWT 在签发后不再受到服务端直接管理(如撤销),在登录场景中需要注意注意:
  1. 服务端的登出不是真正的登出,用户仍然可以拥有 JWT 进行请求,因此需要一些额外手段对 JWT 的有效性进行管理,如用 Redis 对 JWT 进行缓存和生效时间限制,用于验证每个请求的 JWT 是否与缓存一致,登出清除该条缓存。
  1. 服务端修改了一些基本信息后 JWT 无法及时自动同步,如记录了用户权限信息的 JWT 在降低权限的修改后仍可能继续使用的问题,同样需要引入其他机制解决。
  1. JWT 泄露后无法被服务端及时发觉,同样需要引入其他机制解决,如将 JWT 和 Cookie 结合,将 JWT 放入 Cookie 中简化客户端开发,同时降低 JWT 存放不合理导致的安全风险。
如果使用了上面的一些方式维护 JWT,那么其实背离了 JWT 的设计初衷:使服务端不需要维护每个对话的状态,及服务端无状态的目的。这个分歧的关键是 JWT 是自包含的,有状态的,服务端不应该再存储已经签发的 JWT,用 JWT 的系统一般是完全信任 JWT token, 否则就没必要用 JWT,但实际应用中需要考虑到需求的变动带来的技术方案上的调整。
 
 
 

参考

彻底搞懂JWT 知其然更知其所以然 什么是JWT 其特点 应用场景 与其他同类机制的对比(二)_哔哩哔哩_bilibili
我们常见的 JWT 实现(即 JWS 实现),它的头部和载荷都是没有加密的,所以它的目的并不是想隐藏数据,它的目的是防止数据被篡改,这点是通过第三部分 签名 来实现的。请大家务必记住这点,这样JWT 的各种应用场景都能很好的把握了。本视频是内容的第二部分涉及 JWT 的应用场景和跟其他认证机制的对比。, 视频播放量 6863、弹幕量 49、点赞数 274、投硬币枚数 145、收藏人数 216、转发人数 9, 视频作者 老朱的IT圈, 作者简介 一切关于程序员/媛,相关理论知识,工具框架,实践经验。关注我,一块学习,一块成长。,相关视频:Cookie、Session、Token、JWT一次性讲完,【极简入门】15分钟学会JWT的使用,彻底搞懂JWT 知其然更知其所以然 什么是JWT 其特点 应用场景 与其他同类机制的对比(一),10分钟学会什么是jwt【余胜军通俗易懂版本】,什么是JWT ?为什么要使用JWT ?,JWT其实也就这样啦,快手二面:有了Cookie和Session 为什么还要JWT ?你说一下JWT的原理?,Cookie、Session、Token究竟区别在哪?如何进行身份认证,保持用户登录状态?,JWT避坑指南,这些坑真是防不胜防!,CAP理论并不十分严谨,存在较大缺陷,不适用于实际应用,我们应该考虑使用PACELC理论
彻底搞懂JWT 知其然更知其所以然 什么是JWT 其特点 应用场景 与其他同类机制的对比(二)_哔哩哔哩_bilibili