以前分享了一个使用 Spring Security 实现 JWT 身份认证的 Demo,文章地址:适合初学者入门 Spring Security With JWT 的 Demo。 Demo 很是简单,没有介绍到 JWT 存在的一些问题。因此,单独抽了一篇文章出来介绍。为了完成这篇文章,我查阅了不少资料和文献,我以为应该对你们有帮助。html
相关阅读:前端
相比于 Session 认证的方式来讲,使用 token 进行身份认证主要有下面三个优点:web
token 自身包含了身份验证所须要的全部信息,使得咱们的服务器不须要存储 Session 信息,这显然增长了系统的可用性和伸缩性,大大减轻了服务端的压力。可是,也正是因为 token 的无状态,也致使了它最大的缺点:当后端在token 有效期内废弃一个 token 或者更改它的权限的话,不会当即生效,通常须要等到有效期事后才能够。另外,当用户 Logout 的话,token 也还有效。除非,咱们在后端增长额外的处理逻辑。redis
CSRF(Cross Site Request Forgery)通常被翻译为 跨站请求伪造,属于网络攻击领域范围。相比于 SQL 脚本注入、XSS等等安全攻击方式,CSRF 的知名度并无它们高。可是,它的确是每一个系统都要考虑的安全隐患,就连技术帝国 Google 的 Gmail 在早些年也被曝出过存在 CSRF 漏洞,这给 Gmail 的用户形成了很大的损失。数据库
那么究竟什么是 跨站请求伪造 呢?说简单用你的身份去发送一些对你不友好的请求。举个简单的例子:json
小壮登陆了某网上银行,他来到了网上银行的帖子区,看到一个帖子下面有一个连接写着“科学理财,年盈利率过万”,小壮好奇的点开了这个连接,结果发现本身的帐户少了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 中会更好。
使用 Session 进行身份认证的话,须要保存一份信息在服务器端,并且这种方式会依赖到 Cookie(须要 Cookie 保存 SessionId),因此不适合移动端。
可是,使用 token 进行身份认证就不会存在这种问题,由于只要 token 能够被客户端存储就可以使用,并且 token 还能够跨语言使用。
使用 Session 进行身份认证的话,实现单点登陆,须要咱们把用户的 Session 信息保存在一台电脑上,而且还会遇到常见的 Cookie 跨域的问题。可是,使用 token 进行认证的话, token 被保存在客户端,不会存在这些问题。
与之相似的具体相关场景有:
这个问题不存在于 Session 认证方式中,由于在 Session 认证方式中,遇到这种状况的话服务端删除对应的 Session 记录便可。可是,使用 token 认证的方式就很差解决了。咱们也说过了,token 一旦派发出去,若是后端不增长其余逻辑的话,它在失效以前都是有效的。那么,咱们如何解决这个问题呢?查阅了不少资料,总结了下面几种方案:
对于修改密码后 token 还有效问题的解决仍是比较容易的,说一种我以为比较好的方式:使用用户的密码的哈希值对 token 进行签名。所以,若是密码更改,则任何先前的令牌将自动没法验证。
token 有效期通常都建议设置的不太长,那么 token 过时后如何认证,如何实现动态刷新 token,避免用户常常须要从新登陆?
咱们先来看看在 Session 认证中通常的作法:假如 session 的有效期30分钟,若是 30 分钟内用户有访问,就把 session 有效期被延长30分钟。
JWT 最适合的场景是不须要服务端保存用户状态的场景,好比若是考虑到 token 注销和 token 续签的场景话,没有特别好的解决方案,大部分解决方案都给 token 加上了状态,这就有点相似 Session 认证了。