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

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=bank/Transfer?bankId=11&money=10000>科学理财,年盈利率过万</>
导致这个问题很⼤的原因就是: 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 失效,我们直接修改对应⽤户的密钥即可。但是,这样相⽐于前两种引⼊内存数据库带来了危害更⼤,⽐如:1  如果服务是分布式的,则每次发出新的 token 时都必须在多台机器同步密钥。为此,你需要将必须将机密存储在数据库或其他外部服务中,这样和 Session 认证就没太⼤区别了。2  如果⽤户同时在两个浏览器打开系统,或者在⼿机端也打开了系统,如果它从⼀个地⽅将账号退出,那么其他地⽅都要重新进
板栗剥壳机⾏登录,这是不可取的。
保持令牌的有效期限短并经常轮换:很简单的⼀种⽅式。但是,会导致⽤户登录状态不会被持久记录,⽽且需要⽤户经常登录。
蚕蛹虫草
对于修改密码后 token 还有效问题的解决还是⽐较容易的,说⼀种我觉得⽐较好的⽅式:使⽤⽤户的密码的哈希值对 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 给客户端。否则,客户端就重新登录即可。该⽅案的不⾜是:1  需要客户端来配合;2  ⽤户注销的时候需要同时保证两个 token 都⽆效;3  重新请求获取 token 的过程中会有短暂 token 不可⽤的情况(可以通过在客户端设置定时器,当accessToken 快过期的时候,提前去通过 refreshToken 获取新的accessToken)。
总结
JWT 最适合的场景是不需要服务端保存⽤户状态的场景,⽐如如果考虑到 token 注销和 token 续签的场景话,没有特别好的解决⽅案,⼤部分解决⽅案都给 token 加上了状态,这就有点类似 Session 认证了。

本文发布于:2024-09-21 17:51:43,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/4/149882.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:需要   服务端   请求   问题
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议