JWT是什么
JWT概念
JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑用于在各方之间作为JSON对象安全地传输信息。此信息可以验证和信任,因为它是经过数字签名的。可以使用ECHMAC算法对RSA或WTAC算法进行签名。尽管JWT可以被加密以在各方之间提供保密性,但我们将重点关注签名令牌。签名令牌可以验证其中包含的声明的完整性,而加密令牌对其他方隐藏这些声明。当使用公钥/私钥对令牌进行签名时,签名还证明只有持有私钥的一方才是签名方。
JWT认证的流程
- 用户使用用户名和密码向服务端发送登录请求。
- 服务端将接收到的用户名和密码与数据库进行验证。
- 用户名和密码验证通过后,服务端生成一个token,将这个token返回给客户端。
- 客户端接收到服务端返回的token后,将token进行保存。
- 下一次客户端向服务端发送请求时,客户端每次都需要携带token发送到后台。
- 服务端在接收到客户端的请求时,先对token进行验证,验证通过后向客户端返回请求的数据。
图片作者:包包 图片来源: https://www.baobao555.tech/posts/4cc42459/
与传统session认证的区别
session认证的流程
- 用户使用用户名和密码向服务端发送登录请求
- 服务端将接收到的用户名和密码进行验证
- 用户名和密码验证通过后,服务端生成一个session,并将这个session保存在数据库中。
- 同时服务端还会生成一个session id 返回给客户端。
- 客户端接收到服务端返回的session id后,将session id进行保存。
- 下一次客户端向服务端发送请求时,客户端每次都需要携带session id发送到后台。
- 服务端在接收到客户端的请求时,先对session id进行验证,验证通过后向客户端返回请求的数据。
两者的优缺点
- session保存在服务端,而token保存在客户端。
随着用户数量的增加 session认证的服务器开销就会增大,而token不保存在服务端不会增加开销。 在分布式系统中session认证的方法就会失效。 - jwt要保存在客户端限制了jwt中包含的信息大小。
- jwt中不能包含敏感信息,而session中的数据保存在服务端不必担心泄露。
HTTP是一个“无状态”协议,这意味着Web应用程序服务器在响应客户端请求时不会将多个请求链接到任何一个客户端。然而,许多Web应用程序的安全和正常运行都取决于系统能够区分用户并识别用户及其权限。 这就需要一些机制来为一个HTTP请求提供状态。它们使站点能够在会话期间对各用户做出适当的响应,从而保持跟踪用户在应用程序中的活动(请求和响应)。
问题
- 服务端中不保存token如何验证?
- token泄露怎么保证安全?
JWT数据结构
json web token由三部分组成header、payload、Signature三部分组成。
- header 头部
- payload 载荷
- signature 签名
JWT的格式通常是 xxxxx.yyyyy.zzzzz
header
头部通常由两部分组成:token的类型(即 JWT)和正在使用的签名算法(jwt第三部分使用的加密算法),如 HMAC SHA256 或 RSA。 例如:
{
"alg": "HS256",
"typ": "JWT"
}
Base64编码后:
ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9
payload
令牌的第二部分是有效负载,其中包含声明。声明是关于实体(通常是用户)和附加数据的声明。有三种类型的声明:注册声明、公共声明和私人声明。
- 注册声明
这是一套预先确定的声明,不是强制性的,但建议,以提供一套有用的可互操作的声明。其中一些是:
- iss: jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp:jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的.
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
因为token是保存在客户端中,为了减少占用的空间,jwt中的字体要紧凑,所以声明的名称只有三个字符。
- 公开声明
这些可以由使用JWT的人可以当即定义。但为了避免碰撞,它们应在IANA JSON Web 令牌注册表中定义,或定义为包含抗碰撞名称空间的 URI。例如:用户id、账号信息等一些非敏感信息。 - 私人声明
这些是为在同意使用这些索赔且既未登记或公开索赔的当事方之间共享信息而创建的自定义索赔。
例如:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
Base64编码后:
ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAiSm9obiBEb2UiLAogICJhZG1pbiI6IHRydWUKfQ==
Signature
要创建签名部分,您必须使用编码后的头部和有效载荷、密钥、头部中指定的算法并签署该代码。 密钥是存储在服务端,是验证jwt的关键,确保密钥不能泄露。 签名的结构:
HS256(
base64(header)+'.'
+base64(payload)+'.'
+secret
)
将所有放在一起 输出是三个由点分离的 Base64-URL 字符串,这些点在 HTML 和 HTTP 环境中很容易传递,而与基于 XML 的标准(如 SAML)相比更紧凑。 下面显示了一个 JWT,它具有以前的头和有效载荷编码,并且它与一个秘密签名。
ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9.
ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAiSm9obiBEb2UiLAogICJhZG1pbiI6IHRydWUKfQ==.
YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=
总结
1、session认证session id存储在cookie中只需要6个字节,jwt的token需要几百个字节,如果存储的信息更多时占用的字节数也会更多,每次请求流量开销增加几十倍。 2、每次请求都会访问数据库,需要加载、缓存数据,出现以下几种情况:
- 需要用户关键性信息查询(例如:判断用户账号是否有足够的资金完成交易?)
- 需要将一些信息保存进数据库(例如:用户相关的唯一信息,需要根据该信息对用户进行检索)
- 必须从缓存/数据库中查询完整的信息,方便网站生成完整的动态页面内容。
想想你的网站是否会遇到上述情形。这意味着大多数网站不适用 JWT 的无状态特性。为了解决这个问题,就需要 JWT 变得更大,而且需要使用 CPU 来计算签名,就会导致比传统会话慢许多。
3、JWT 的卖点之一就是加密签名,由于这个特性,接收方得以验证 JWT 是否有效且被信任。 但是,其实在过去 20 年中几乎每一个框架对于普通会话 Cookie 都可以获得很好的加密签名处理。这意味着你可以获得与 JWT 完全一致的效果,况且大多数 Web 身份认证应用中,JWT 都会被存储到 Cookie 中,这就是说你有了两个层面的签名。 听着似乎很赞,但是没有任何优势,为此,你需要花费两倍的 CPU 开销来验证签名。对于有着严格性能要求的 Web 应用,这并不理想,尤其对于单线程环境。
|