一文带你搞懂 JWT 常见概念 & 优缺点
JWT 的劣势
相比于 Session 认证的形式来说,使用 JWT 进行身份认证次要有上面 4 个劣势。
无状态
JWT 自身蕴含了身份考据所需要的所有信息,因此,咱们的服务器不需要存储 Session 信息。这显然减少了零碎的可用性和伸缩性,大大加重了服务端的压力。
不过,也正是因为 JWT 的无状态,也导致了它最大的缺点:不可控!
就比方说,咱们想要在 JWT 有效期内废除一个 JWT 或者更改它的权限的话,并不会立即失效,通常需要等到有效期过后才可能。再比方说,当用户 Logout 的话,JWT 也还无效。除非,咱们在后端减少额定的处理逻辑比如将生效的 JWT 存储起来,后端先考据 JWT 是否无效再进行处理。具体的解决办法,咱们会在前面的内容中粗疏介绍到,这里只是简略提一下。
无效避免了 CSRF 攻打
CSRF(Cross Site Request Forgery)一般被翻译为 跨站请求伪造,属于网络攻击领域范畴。相比于 SQL 脚本注入、XSS 等安全攻击方式,CSRF 的知名度并没有它们高。然而,它的确是咱们开发零碎时必须要考虑的安全隐患。就连业内技术标杆 Google 的产品 Gmail 也曾在 2007 年的时候爆出过 CSRF 漏洞,这给 Gmail 的用户造成了很大的损失。
那么究竟什么是跨站请求伪造呢?简略来说就是用你的身份去做一些不好的事件(发送一些对你不敌对的请求比如恶意转账)。
举个简略的例子:小壮登录了某网上银行,他来到了网上银行的帖子区,看到一个帖子上面有一个链接写着“迷信理财,年盈利率过万”,小壮好奇的点开了这个链接,后果发现自己的账户少了 10000 元。这是这么回事呢?原来黑客在链接中藏了一个请求,这个请求间接利用小壮的身份给银行发送了一个转账请求,也就是通过你的 Cookie 向银行收回请求。
CSRF 攻打需要依赖 Cookie,Session 认证中 Cookie 中的 SessionID 是由阅读器发送到服务端的,只需收回请求,Cookie 就会被携带。借助这个个性,即使黑客无奈获取你的 SessionID,只需让你正点攻打链接,就可能达到攻打成果。
另外,并不是必须点击链接才可能达到攻打成果,很多时候,只需你打开了某个页面,CSRF 攻打就会发生。
复制代码
那为什么 JWT 不会存在这种问题呢?
一般情况下咱们使用 JWT 的话,在咱们登录胜利获得 JWT 之后,一般会抉择存放在 localStorage 中。前端的每一个请求后续都会附带上这个 JWT,整个过程压根不会涉及到 Cookie。因此,即使你点击了非法链接发送了请求到服务端,这个非法请求也是不会携带 JWT 的,所以这个请求将是非法的。
总结来说就一句话:使用 JWT 进行身份考据不需要依赖 Cookie,因此可能避免 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 {
XSSRequestWrapper wrappedRequest =
new XSSRequestWrapper((HttpServletRequest) request);
chain.doFilter(wrappedRequest, response);
}
// other methods
}
复制代码
适合移动端利用
使用 Session 进行身份认证的话,需要保存一份信息在服务器端,而且这种形式会依赖到 Cookie(需要 Cookie 保存 SessionId),所以不适合移动端。
然而,使用 JWT 进行身份认证就不会存在这种问题,因为只需 JWT 可能被客户端存储就能够使用,而且 JWT 还可能跨语言使用。
单点登录敌对
使用 Session 进行身份认证的话,实现单点登录,需要咱们把用户的 Session 信息保存在一台电脑上,并且还会遇到常见的 Cookie 跨域的问题。然而,使用 JWT 进行认证的话,JWT 被保存在客户端,不会存在这些问题。
JWT 身份认证常见问题及解决办法
登记登录等场景下 JWT 还无效
与之类似的具体相干场景有:
退出登录;
修改明码;
服务端修改了某个用户具备的权限或者角色;
用户的帐户被封禁 / 删除;
用户被服务端强制登记;
用户被踢下线;
……
这个问题不存在于 Session 认证形式中,因为在 Session 认证形式中,遇到这种情况的话服务端删除对应的 Session 记录即可。然而,使用 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、修改密钥 (Secret) :
咱们为每个用户都创建一个专属密钥,如果咱们想让某个 JWT 生效,咱们间接修改对应用户的密钥即可。然而,这样相比于前两种引入内存数据库带来了危害更大:
如果服务是分布式的,则每次收回新的 JWT 时都必须在多台机器同步密钥。为此,你需要将密钥存储在数据库或其余内部服务中,这样和 Session 认证就没太大区别了。
如果用户同时在两个阅读器打开零碎,或者在手机端也打开了零碎,如果它从一个地方将账号退出,那么其余地方都要从新进行登录,这是不可取的。
4、保持令牌的有效期限短并常常轮换
很简略的一种形式。然而,会导致用户登录状态不会被持久记录,而且需要用户常常登录。
另外,对于修改明码后 JWT 还无效问题的解决还是比较容易的。说一种我感觉比较好的形式:使用用户的明码的哈希值对 JWT 进行签名。因此,如果明码更改,则任何先前的令牌将主动无奈考据。
JWT 的续签问题
JWT 有效期一般都倡导设置的不太长,那么 JWT 过期后如何认证,如何实现动静刷新 JWT,避免用户常常需要从新登录?
咱们先来看看在 Session 认证中一般的做法:假如 Session 的有效期 30 分钟,如果 30 分钟内用户有拜访,就把 Session 有效期缩短 30 分钟。
JWT 认证的话,咱们应该如何解决续签问题呢?查阅了很多资料,我简略总结了上面 4 种打算:
1、类似于 Session 认证中的做法
这种打算满足于大部分场景。假设服务端给的 JWT 有效期设置为 30 分钟,服务端每次进行校验时,如果发现 JWT 的有效期马上快过期了,服务端就重重生成 JWT 给客户端。客户端每次请求都查看新旧 JWT,如果不一致,则更新本地的 JWT。这种做法的问题是仅仅在快过期的时候请求才会更新 JWT , 对客户端不是很敌对。
2、每次请求都返回新 JWT
这种打算的的思路很简略,然而,开销会比较大,特地是在服务端要存储保护 JWT 的情况下。
3、JWT 有效期设置到中午
这种打算是一种折衷的打算,保障了大部分用户白天可能失常登录,实用于对安全性申请不高的零碎。
4、用户登录返回两个 JWT
第一个是 accessJWT,它的过期工夫 JWT 本身的过期工夫比如半个小时,另外一个是 refreshJWT 它的过期工夫更长一点比如为 1 天。客户端登录后,将 accessJWT 和 refreshJWT 保存在本地,每次拜访将 accessJWT 传给服务端。服务端校验 accessJWT 的有效性,如果过期的话,就将 refreshJWT 传给服务端。如果无效,服务端就生成新的 accessJWT 给客户端。否则,客户端就从新登录即可。
这种打算的不足是:
需要客户端来配合;
用户登记的时候需要同时保障两个 JWT 都有效;
从新请求获取 JWT 的过程中会有短暂 JWT 不可用的情况(可能通过在客户端设置定时器,当 accessJWT 快过期的时候,提早去通过 refreshJWT 获取新的 accessJWT)。
总结
JWT 其中一个很重要的劣势是无状态,但实际上,咱们想要在实际我的项目中正当使用 JWT 的话,也还是需要保存 JWT 信息。
JWT 也不是银弹,也有很多缺点,具体是抉择 JWT 还是 Session 打算还是要看我的项目的具体需要。万万不可尬吹 JWT,而看不起其余身份认证打算。