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