一文带你搞懂 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,而看不起其他身份认证计划。