简单来说就是用你的身份去做一些不好的事情

在本文中,我介绍了 JWT 的基本概念:

在本文中,我们来讨论一下JWT认证的优缺点以及常见问题的解决方案。

智威汤逊的优势

与Session认证相比,使用JWT进行身份认证主要有以下四个优点。

无状态

JWT 本身包含了认证所需的所有信息,因此我们的服务器不需要存储 Session 信息。这明显提高了系统的可用性和可扩展性,大大降低了服务器的压力。

然而,正是因为JWT的无状态,也导致了它最大的劣势:不可控!

例如,如果我们想在 JWT 的有效期内丢弃一个 JWT 或者更改它的权限,它不会立即生效,通常我们需要等到有效期结束。再比如,当用户注销时,JWT 仍然有效。除非,我们在后端添加额外的处理逻辑,比如存储无效的 JWT,后端在处理之前验证 JWT 是否有效。具体的解决方案会在后面的内容中详细介绍,这里只是简单的提及。

有效避免 CSRF 攻击

CSRF(Cross Site Request Forgery)一般翻译为Cross-Site Request Forgery,属于网络攻击领域。与 SQL 脚本注入和 XSS 等安全攻击方法相比,CSRF 并不像它们那样广为人知。但是,这确实是我们在开发系统时必须考虑的安全风险。就连业界技术标杆谷歌的产品Gmail也在2007年出现了CSRF漏洞,给Gmail用户造成了巨大损失。

那么究竟什么是跨站请求伪造?简单来说就是利用你的身份做坏事(向你发送一些不友好的请求,比如恶意转账)。

举个简单的例子:小庄登录网银,来到网银发帖区,看到一个帖子下有一个链接,上面写着“科学理财,年利润率超万” ”,小庄好奇点开这个链接,发现我的账户少了一万块钱。是这样吗?原来,黑客在链接中隐藏了一个请求。该请求直接使用小庄的身份向银行发送转账请求,即通过您的cookie向银行发送请求。

科学理财,年盈利率过万

CSRF 攻击需要依赖 cookie。会话认证中cookie中的SessionID由浏览器发送给服务器。只要发出请求,就会携带cookie。有了这个功能,即使黑客无法获取到你的SessionID,只要你误点击了攻击链接,就可以达到攻击效果。

图片[1]-简单来说就是用你的身份去做一些不好的事情-唐朝资源网

另外,不需要点击链接即可达到攻击效果。很多情况下,只要打开某个页面,就会发生CSRF攻击。

为什么JWT没有这个问题?

一般来说,如果我们使用JWT,在我们成功登录获取JWT后,我们通常会选择将其存储在localStorage中。前端的每一个请求都会伴随着这个JWT,整个过程完全不会涉及cookies。因此,即使点击了非法链接,向服务器发送请求,非法请求也不会携带JWT,所以该请求是非法的。

一句话总结:使用JWT的认证不需要依赖cookies,可以避免CSRF攻击。

但是,也存在 XSS 攻击的风险。为避免 XSS 攻击,您可以选择将 JWT 存储在标记为 httpOnly 的 cookie 中。但是,这导致您必须自己提供 CSRF 保护,因此我们通常不会在实际项目中这样做。

避免 XSS 攻击的常用方法是过滤掉请求中存在 XSS 攻击风险的可疑字符串。

在 Spring 项目中,我们通常通过创建 XSS 过滤器来做到这一点。

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class XSSFilter implements Filter {
    @Override

    public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) throws IOException, ServletException {
        Xs-s-requestWrapper wrappedRequest =
          new Xs-s-requestWrapper((HttpServletRequest) request);
        chain.doFilter(wrappedRequest, response);
    }
    // other methods
}

适用于移动应用

如果使用Session进行认证,需要在服务器端保存一条信息,而且这种方式会依赖cookies(需要cookies保存SessionId),所以不适合移动端。

但是使用JWT进行认证就没有这个问题,因为只要JWT能被客户端存储就可以使用,而且JWT也可以跨语言使用。

单点登录友好

如果使用Session进行认证,要实现单点登录,需要将用户的Session信息保存在电脑上,也会遇到常见的跨域cookie问题。但是如果使用JWT进行认证,JWT存储在客户端,就不存在这些问题了。

JWT认证常见问题及解决方案JWT在注销登录等场景下依然有效

类似的具体相关场景有:

在会话认证模式下不存在这个问题,因为在会话认证模式下,如果发生这种情况,服务器可以删除相应的会话记录。但是,使用 JWT 认证的方式并不容易解决。我们也说过,JWT一旦被调度,如果后端没有添加其他逻辑,它一直有效,直到它失效。

那么我们如何解决这个问题呢?在查阅了大量资料后,我简单总结了以下4个方案:

1、将 JWT 保存到内存数据库

将 JWT 存储在 DB 中,Redis 内存数据库在这里是一个不错的选择。如果您需要使 JWT 失效,只需从 Redis 中删除 JWT。但是这样会导致每次使用 JWT 发送请求时都要查询 DB 是否存在 JWT,违反了 JWT 的无状态原则。

2、黑名单机制

与上述方法类似,使用Redis等内存数据库维护黑名单。如果您希望 JWT 失败,可以直接将 JWT 添加到黑名单中。那么,每次使用 JWT 发出请求时,都会先判断该 JWT 是否存在于黑名单中。

前两种解决方案的核心是存储有效的 JWT 或将指定的 JWT 列入黑名单。

虽然这两种方案违反了JWT的无状态原则,但我们在实际项目中通常会使用这两种方案。

3、修改密码:

我们为每个用户创建一个专有密钥。如果我们想使一个 JWT 失效,我们可以直接修改对应用户的 key。但是,这比前两种引入内存数据库的危害更大:

4、保持令牌在短期和频繁轮换中有效

图片[2]-简单来说就是用你的身份去做一些不好的事情-唐朝资源网

一个非常简单的方法。但是用户的登录状态并没有永久记录,需要用户经常登录。

另外,修改密码后JWT仍然有效的问题也比较容易解决。说一种我认为更好的方法:使用用户密码的哈希来签署 JWT。所以如果密码被更改,任何以前的令牌都会自动验证失败。

JWT 续订问题

一般建议JWT的有效期不要太长,那么JWT过期后如何认证,如何动态刷新JWT避免用户频繁登录?

我们先看一下会话认证中的一般做法:如果会话有效期为30分钟,如果用户在30分钟内有访问权限,则会话有效期延长30分钟。

如果JWT通过了认证,我们应该如何解决续费问题?在查阅了大量资料后,我简单总结了以下4个方案:

1、类似于会话认证

此解决方案足以满足大多数情况。假设服务器给的JWT有效期设置为30分钟,每次服务器进行验证,如果发现JWT的有效期即将到期,服务器就会重新生成JWT给客户端。客户端检查每个请求的新旧 JWT,如果不一致则更新本地 JWT。这种方式的问题是,请求只有在即将过期时才会更新JWT,对客户端不太友好。

2、对每个请求返回一个新的 JWT

这个方案的思路很简单,但是开销会比较大,尤其是服务器需要存储和维护JWT的时候。

3、JWT 有效期至午夜

此方案为折中方案,保证大部分用户白天都能正常登录,适用于安全要求不高的系统。

4、用户登录返回两个 JWT

第一个是accessJWT,它的过期时间是JWT本身的过期时间,比如半小时,另一个是refreshJWT,它的过期时间更长,比如1天。客户端登录后,将accessJWT和refreshJWT保存在本地,每次访问都将accessJWT传递给服务器。服务端验证accessJWT的合法性,如果过期则将refreshJWT传给服务端。如果有效,服务器会为客户端生成一个新的 accessJWT。否则,客户端可以重新登录。

图片[3]-简单来说就是用你的身份去做一些不好的事情-唐朝资源网

这种方案的缺点是:

总结

JWT的一个重要优点是它是无状态的,但实际上,如果我们想在实际项目中合理使用JWT,还是需要保存JWT信息的。

JWT 不是灵丹妙药,有很多缺陷。选择 JWT 还是 Session 解决方案取决于项目的具体需求。不要不好意思吹嘘 JWT,看不起其他认证方案。

另外,也可以直接用普通的Token(随机生成,没有具体信息)配合Redis进行身份认证,无需JWT。我在第8期推荐的Sa-Token项目是一个比较完善的基于JWT的认证方案,支持自动续费、踢人下线、账号封禁、同端互斥登录。有兴趣的朋友可以看看。

参考后记

专注Java原创干货分享,初级开源JavaGuide(《Java学习+面试指南》涵盖了大部分Java程序员需要掌握的核心知识。准备Java面试,JavaGuide是首选!),目前拥有 120k+ 颗星。

原创不易,欢迎点赞分享,欢迎关注我的掘金账号,我会继续分享原创干货!来吧,去吧!

如果这篇文章对你有帮助,请点赞和分享,继续分享和创作优质文章对我来说非常重要。谢谢

分类:

Java面试进阶指南Java面试题/知识点收集

技术要点:

相关文章:

© 版权声明
THE END
喜欢就支持一下吧
点赞213 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片