乐趣区

关于java:JWT-身份认证优缺点分析以及常见问题解决方案

之前分享了一个应用 Spring Security 实现 JWT 身份认证的 Demo,文章地址:适宜初学者入门 Spring Security With JWT 的 Demo。Demo 非常简单,没有介绍到 JWT 存在的一些问题。所以,独自抽了一篇文章进去介绍。为了实现这篇文章,我查阅了很多材料和文献,我感觉应该对大家有帮忙。

相干浏览:

  • 《一问带你辨别分明 Authentication,Authorization 以及 Cookie、Session、Token》
  • 适宜初学者入门 Spring Security With JWT 的 Demo
  • Spring Boot 应用 JWT 进行身份和权限验证

Token 认证的劣势

相比于 Session 认证的形式来说,应用 token 进行身份认证次要有上面三个劣势:

1. 无状态

token 本身蕴含了身份验证所须要的所有信息,使得咱们的服务器不须要存储 Session 信息,这显然减少了零碎的可用性和伸缩性,大大加重了服务端的压力。然而,也正是因为 token 的无状态,也导致了它最大的毛病:当后端在 token 有效期内废除一个 token 或者更改它的权限的话,不会立刻失效,个别须要等到有效期过后才能够。另外,当用户 Logout 的话,token 也还无效。除非,咱们在后端减少额定的解决逻辑。

2. 无效防止了 CSRF 攻打

CSRF(Cross Site Request Forgery)个别被翻译为 跨站申请伪造,属于网络攻击畛域范畴。相比于 SQL 脚本注入、XSS 等等平安攻击方式,CSRF 的知名度并没有它们高。然而, 它确实是每个零碎都要思考的安全隐患,就连技术帝国 Google 的 Gmail 在早些年也被曝出过存在 CSRF 破绽,这给 Gmail 的用户造成了很大的损失。

那么到底什么是 跨站申请伪造 呢?说简略用你的身份去发送一些对你不敌对的申请。举个简略的例子:

小壮登录了某网上银行,他来到了网上银行的帖子区,看到一个帖子上面有一个链接写着“迷信理财,年盈利率过万”,小壮好奇的点开了这个链接,后果发现自己的账户少了 10000 元。这是这么回事呢?原来黑客在链接中藏了一个申请,这个申请间接利用小壮的身份给银行发送了一个转账申请, 也就是通过你的 Cookie 向银行发出请求。

<a src="http://www.mybank.com/Transfer?bankId=11&money=10000"> 迷信理财,年盈利率过万 </a>

导致这个问题很大的起因就是:Session 认证中 Cookie 中的 session_id 是由浏览器发送到服务端的,借助这个个性,攻击者就能够通过让用户正点攻打链接,达到攻打成果。

那为什么 token 不会存在这种问题呢?

我是这样了解的:个别状况下咱们应用 JWT 的话,在咱们登录胜利取得 token 之后,个别会抉择寄存在 local storage 中。而后咱们在前端通过某些形式会给每个发到后端的申请加上这个 token, 这样就不会呈现 CSRF 破绽的问题。因为,即便有个你点击了非法链接发送了申请到服务端,这个非法申请是不会携带 token 的,所以这个申请将是非法的。

然而这样会存在 XSS 攻打中被盗的危险,为了防止 XSS 攻打,你能够抉择将 token 存储在标记为httpOnly 的 cookie 中。然而,这样又导致了你必须本人提供 CSRF 爱护。

具体采纳下面哪两种形式存储 token 呢,大部分状况下寄存在 local storage 下都是最好的抉择,某些状况下可能须要寄存在标记为httpOnly 的 cookie 中会更好。

3. 适宜挪动端利用

应用 Session 进行身份认证的话,须要保留一份信息在服务器端,而且这种形式会依赖到 Cookie(须要 Cookie 保留 SessionId),所以不适宜挪动端。

然而,应用 token 进行身份认证就不会存在这种问题,因为只有 token 能够被客户端存储就可能应用,而且 token 还能够跨语言应用。

4. 单点登录敌对

应用 Session 进行身份认证的话,实现单点登录,须要咱们把用户的 Session 信息保留在一台电脑上,并且还会遇到常见的 Cookie 跨域的问题。然而,应用 token 进行认证的话,token 被保留在客户端,不会存在这些问题。

Token 认证常见问题以及解决办法

1. 登记登录等场景下 token 还无效

与之类似的具体相干场景有:

  1. 退出登录;
  2. 批改明码;
  3. 服务端批改了某个用户具备的权限或者角色;
  4. 用户的帐户被删除 / 暂停。
  5. 用户由管理员登记;

这个问题不存在于 Session 认证形式中,因为在 Session 认证形式中,遇到这种状况的话服务端删除对应的 Session 记录即可。然而,应用 token 认证的形式就不好解决了。咱们也说过了,token 一旦派发进来,如果后端不减少其余逻辑的话,它在生效之前都是无效的。那么,咱们如何解决这个问题呢?查阅了很多材料,总结了上面几种计划:

  • 将 token 存入内存数据库:将 token 存入 DB 中,redis 内存数据库在这里是是不错的抉择。如果须要让某个 token 生效就间接从 redis 中删除这个 token 即可。然而,这样会导致每次应用 token 发送申请都要先从 DB 中查问 token 是否存在的步骤,而且违反了 JWT 的无状态准则。
  • 黑名单机制 :和下面的形式相似,应用内存数据库比方 redis 保护一个黑名单,如果想让某个 token 生效的话就间接将这个 token 退出到  黑名单 即可。而后,每次应用 token 进行申请的话都会先判断这个 token 是否存在于黑名单中。
  • 批改密钥 (Secret) : 咱们为每个用户都创立一个专属密钥,如果咱们想让某个 token 生效,咱们间接批改对应用户的密钥即可。然而,这样相比于前两种引入内存数据库带来了危害更大,比方:① 如果服务是分布式的,则每次收回新的 token 时都必须在多台机器同步密钥。为此,你须要将必须将秘密存储在数据库或其余内部服务中,这样和 Session 认证就没太大区别了。② 如果用户同时在两个浏览器关上零碎,或者在手机端也关上了零碎,如果它从一个中央将账号退出,那么其余中央都要从新进行登录,这是不可取的。
  • 放弃令牌的有效期限短并常常轮换:很简略的一种形式。然而,会导致用户登录状态不会被长久记录,而且须要用户常常登录。

对于批改明码后 token 还无效问题的解决还是比拟容易的,说一种我感觉比拟好的形式:应用用户的明码的哈希值对 token 进行签名。因而,如果明码更改,则任何先前的令牌将主动无奈验证。

2.token 的续签问题

token 有效期个别都倡议设置的不太长,那么 token 过期后如何认证,如何实现动静刷新 token,防止用户常常须要从新登录?

咱们先来看看在 Session 认证中个别的做法:如果 session 的有效期 30 分钟,如果 30 分钟内用户有拜访,就把 session 有效期被缩短 30 分钟。

  1. 相似于 Session 认证中的做法:这种计划满足于大部分场景。假如服务端给的 token 有效期设置为 30 分钟,服务端每次进行校验时,如果发现 token 的有效期马上快过期了,服务端就从新生成 token 给客户端。客户端每次申请都查看新旧 token,如果不统一,则更新本地的 token。这种做法的问题是仅仅在快过期的时候申请才会更新 token , 对客户端不是很敌对。
  2. 每次申请都返回新 token : 这种计划的的思路很简略,然而,很显著,开销会比拟大。
  3. token 有效期设置到中午:这种计划是一种折衷的计划,保障了大部分用户白天能够失常登录,实用于对安全性要求不高的零碎。
  4. 用户登录返回两个 token:第一个是 acessToken,它的过期工夫 token 自身的过期工夫比方半个小时,另外一个是 refreshToken 它的过期工夫更长一点比方为 1 天。客户端登录后,将 accessToken 和 refreshToken 保留在本地,每次拜访将 accessToken 传给服务端。服务端校验 accessToken 的有效性,如果过期的话,就将 refreshToken 传给服务端。如果无效,服务端就生成新的 accessToken 给客户端。否则,客户端就从新登录即可。该计划的有余是:① ️须要客户端来配合;② ️用户登记的时候须要同时保障两个 token 都有效;③ 从新申请获取 token 的过程中会有短暂 token 不可用的状况(能够通过在客户端设置定时器,当 accessToken 快过期的时候,提前去通过 refreshToken 获取新的 accessToken)。

总结

JWT 最适宜的场景是不须要服务端保留用户状态的场景,比方如果思考到 token 登记和 token 续签的场景话,没有特地好的解决方案,大部分解决方案都给 token 加上了状态,这就有点相似 Session 认证了。

Reference

  • JWT 超详细分析
  • https://medium.com/devgorilla/how-to-log-out-when-using-jwt-a8c7823e8a6
  • https://medium.com/@agungsantoso/csrf-protection-with-json-web-tokens-83e0f2fcbcc
  • Invalidating JSON Web Tokens
退出移动版