[docs improve]完善 JWT 部分的内容

This commit is contained in:
guide 2022-06-09 20:37:30 +08:00
parent 6b9987fabb
commit fa09190dd3
4 changed files with 113 additions and 53 deletions

View File

@ -113,7 +113,7 @@ JRE 是 Java 运行时环境。它是运行已编译 Java 程序所需的所有
>
> 基于以上这些原因OpenJDK 还是有存在的必要的!
![oracle-jdk-release-cadence.jpg](./images/oracle-jdk-release-cadence.jpg)
![oracle jdk release cadence](./images/oracle-jdk-release-cadence.jpg)
🌈 拓展一下:

View File

@ -5,29 +5,41 @@ tag:
- 安全
---
在 [JWT 基本概念详解](https://javaguide.cn/system-design/security/jwt-intro.html)这篇文章中,我介绍了:
- 什么是 JWT?
- JWT 由哪些部分组成?
- 如何基于 JWT 进行身份验证?
- JWT 如何防止 Token 被篡改?
- 如何加强 JWT 的安全性?
这篇文章,我们一起探讨一下 JWT 身份认证的优缺点以及常见问题的解决办法。
## JWT 的优势
相比于 Session 认证的方式来说,使用 Token 进行身份认证主要有下面四个优势:
相比于 Session 认证的方式来说,使用 JWT 进行身份认证主要有下面 4 个优势。
### 无状态
Token 自身包含了身份验证所需要的所有信息,因此,我们的服务器不需要存储 Session 信息。这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
JWT 自身包含了身份验证所需要的所有信息,因此,我们的服务器不需要存储 Session 信息。这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
不过,也正是由于 Token 的无状态也导致了它最大的缺点当后端在Token 有效期内废弃一个 Token 或者更改它的权限的话,不会立即生效,一般需要等到有效期过后才可以。另外,当用户 Logout 的话Token 也还有效。除非,我们在后端增加额外的处理逻辑比如将失效的 Token 存储起来,后端先验证 Token 是否有效再进行处理。
不过,也正是由于 JWT 的无状态,也导致了它最大的缺点:**不可控!**
就比如说,我们想要在 JWT 有效期内废弃一个 JWT 或者更改它的权限的话,并不会立即生效,通常需要等到有效期过后才可以。再比如说,当用户 Logout 的话JWT 也还有效。除非,我们在后端增加额外的处理逻辑比如将失效的 JWT 存储起来,后端先验证 JWT 是否有效再进行处理。具体的解决办法,我们会在后面的内容中详细介绍到,这里只是简单提一下。
### 有效避免了 CSRF 攻击
**CSRFCross Site Request Forgery** 一般被翻译为 **跨站请求伪造**,属于网络攻击领域范围。相比于 SQL 脚本注入、XSS 等安全攻击方式CSRF 的知名度并没有它们高。但是,它的确是每个系统都要考虑的安全隐患,就连技术帝国 Google 的 Gmail 在早些年也被曝出过存在 CSRF 漏洞,这给 Gmail 的用户造成了很大的损失。
**CSRFCross Site Request Forgery** 一般被翻译为 **跨站请求伪造**,属于网络攻击领域范围。相比于 SQL 脚本注入、XSS 等安全攻击方式CSRF 的知名度并没有它们高。但是,它的确是我们开发系统时必须要考虑的安全隐患。就连业内技术标杆 Google 的产品 Gmail 也曾在 2007 年的时候爆出过 CSRF 漏洞,这给 Gmail 的用户造成了很大的损失。
那么究竟什么是 **跨站请求伪造** 呢?说简单用你的身份去发送一些对你不友好的请求。
**那么究竟什么是跨站请求伪造呢?** 简单来说就是用你的身份去做一些不好的事情(发送一些对你不友好的请求比如恶意转账)
举个简单的例子小壮登录了某网上银行他来到了网上银行的帖子区看到一个帖子下面有一个链接写着“科学理财年盈利率过万”小壮好奇的点开了这个链接结果发现自己的账户少了10000元。这是这么回事呢原来黑客在链接中藏了一个请求这个请求直接利用小壮的身份给银行发送了一个转账请求也就是通过你的 Cookie 向银行发出请求。
举个简单的例子:小壮登录了某网上银行,他来到了网上银行的帖子区,看到一个帖子下面有一个链接写着“科学理财,年盈利率过万”,小壮好奇的点开了这个链接,结果发现自己的账户少了 10000 元。这是这么回事呢?原来黑客在链接中藏了一个请求,这个请求直接利用小壮的身份给银行发送了一个转账请求,也就是通过你的 Cookie 向银行发出请求。
```html
<a src="http://www.mybank.com/Transfer?bankId=11&money=10000">科学理财,年盈利率过万</a>
```
CSRF 攻击需要依赖 Cookie Session 认证中 Cookie 中的 `SessionID` 是由浏览器发送到服务端的只要发出请求Cookie 就会被携带。借助这个特性,即使黑客无法获取你的 `SessionID`,只要让你误点攻击链接,就可以达到攻击效果。
CSRF 攻击需要依赖 Cookie Session 认证中 Cookie 中的 `SessionID` 是由浏览器发送到服务端的只要发出请求Cookie 就会被携带。借助这个特性,即使黑客无法获取你的 `SessionID`,只要让你误点攻击链接,就可以达到攻击效果。
另外并不是必须点击链接才可以达到攻击效果很多时候只要你打开了某个页面CSRF 攻击就会发生。
@ -35,15 +47,15 @@ CSRF 攻击需要依赖 Cookie Session 认证中 Cookie 中的 `SessionID`
<img src="http://www.mybank.com/Transfer?bankId=11&money=10000" />
```
**那为什么 Token 不会存在这种问题呢?**
**那为什么 JWT 不会存在这种问题呢?**
一般情况下我们使用 JWT 的话,在我们登录成功获得 Token 之后,一般会选择存放在 localStorage 中。前端的每一个请求后续都会附带上这个 Token,整个过程压根不会涉及到 Cookie。因此即使你点击了非法链接发送了请求到服务端这个非法请求也是不会携带 Token 的,所以这个请求将是非法的。
一般情况下我们使用 JWT 的话,在我们登录成功获得 JWT 之后,一般会选择存放在 localStorage 中。前端的每一个请求后续都会附带上这个 JWT整个过程压根不会涉及到 Cookie。因此即使你点击了非法链接发送了请求到服务端这个非法请求也是不会携带 JWT 的,所以这个请求将是非法的。
总结来说就一句话:**使用 JWT 进行身份验证不需要依赖 Cookie ,因此可以避免 CSRF 攻击。**
不过,这样也会存在 XSS 攻击的风险。为了避免 XSS 攻击,你可以选择将 Token 存储在标记为`httpOnly` 的 Cookie 中。但是这样又导致了你必须自己提供CSRF 保护,因此,实际项目中我们通常也不会这么做。
不过,这样也会存在 XSS 攻击的风险。为了避免 XSS 攻击,你可以选择将 JWT 存储在标记为`httpOnly` 的 Cookie 中。但是,这样又导致了你必须自己提供 CSRF 保护,因此,实际项目中我们通常也不会这么做。
常见的避免 XSS 攻击的方式是过滤掉请求中存在 XSS 攻击风险的可疑字符串。
常见的避免 XSS 攻击的方式是过滤掉请求中存在 XSS 攻击风险的可疑字符串。
在 Spring 项目中,我们一般是通过创建 XSS 过滤器来实现的。
@ -51,11 +63,11 @@ CSRF 攻击需要依赖 Cookie Session 认证中 Cookie 中的 `SessionID`
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class XSSFilter implements Filter {
@Override
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
XSSRequestWrapper wrappedRequest =
XSSRequestWrapper wrappedRequest =
new XSSRequestWrapper((HttpServletRequest) request);
chain.doFilter(wrappedRequest, response);
}
@ -68,52 +80,98 @@ public class XSSFilter implements Filter {
使用 Session 进行身份认证的话,需要保存一份信息在服务器端,而且这种方式会依赖到 Cookie需要 Cookie 保存 `SessionId`),所以不适合移动端。
但是,使用 Token 进行身份认证就不会存在这种问题,因为只要 Token 可以被客户端存储就能够使用,而且 Token 还可以跨语言使用。
但是,使用 JWT 进行身份认证就不会存在这种问题,因为只要 JWT 可以被客户端存储就能够使用,而且 JWT 还可以跨语言使用。
### 单点登录友好
使用 Session 进行身份认证的话,实现单点登录,需要我们把用户的 Session 信息保存在一台电脑上,并且还会遇到常见的 Cookie 跨域的问题。但是,使用 Token 进行认证的话, Token 被保存在客户端,不会存在这些问题。
使用 Session 进行身份认证的话,实现单点登录,需要我们把用户的 Session 信息保存在一台电脑上,并且还会遇到常见的 Cookie 跨域的问题。但是,使用 JWT 进行认证的话, JWT 被保存在客户端,不会存在这些问题。
## JWT 身份认证常见问题及解决办法
### 注销登录等场景下 Token 还有效
### 注销登录等场景下 JWT 还有效
与之类似的具体相关场景有:
- 退出登录;
- 修改密码;
- 服务端修改了某个用户具有的权限或者角色;
- 用户的帐户被删除/暂停。
- 用户由管理员注销;
- 用户的帐户被封禁/删除;
- 用户被服务端强制注销;
- 用户被踢下线;
- ......
这个问题不存在于 Session 认证方式中,因为在 Session 认证方式中,遇到这种情况的话服务端删除对应的 Session 记录即可。但是,使用 Token 认证的方式就不好解决了。我们也说过了Token 一旦派发出去,如果后端不增加其他逻辑的话,它在失效之前都是有效的。那么,我们如何解决这个问题呢?查阅了很多资料,总结了下面几种方案:
这个问题不存在于 Session 认证方式中,因为在 Session 认证方式中,遇到这种情况的话服务端删除对应的 Session 记录即可。但是,使用 JWT 认证的方式就不好解决了。我们也说过了,JWT 一旦派发出去,如果后端不增加其他逻辑的话,它在失效之前都是有效的。
- **将 Token 存入内存数据库**:将 Token 存入 DB 中Redis 内存数据库在这里是不错的选择。如果需要让某个 Token 失效就直接从 Redis 中删除这个 Token 即可。但是,这样会导致每次使用 Token 发送请求都要先从 DB 中查询 Token 是否存在的步骤,而且违背了 JWT 的无状态原则。
- **黑名单机制**:和上面的方式类似,使用内存数据库比如 Redis 维护一个黑名单,如果想让某个 Token 失效的话就直接将这个 Token 加入到 **黑名单** 即可。然后,每次使用 Token 进行请求的话都会先判断这个 Token 是否存在于黑名单中。
- **修改密钥 (Secret)** : 我们为每个用户都创建一个专属密钥,如果我们想让某个 Token 失效我们直接修改对应用户的密钥即可。但是这样相比于前两种引入内存数据库带来了危害更大比如1) 如果服务是分布式的,则每次发出新的 Token 时都必须在多台机器同步密钥。为此,你需要将密钥存储在数据库或其他外部服务中,这样和 Session 认证就没太大区别了。 2) 如果用户同时在两个浏览器打开系统,或者在手机端也打开了系统,如果它从一个地方将账号退出,那么其他地方都要重新进行登录,这是不可取的。
- **保持令牌的有效期限短并经常轮换** :很简单的一种方式。但是,会导致用户登录状态不会被持久记录,而且需要用户经常登录。
那我们如何解决这个问题呢?查阅了很多资料,我简单总结了下面 4 种方案:
对于修改密码后 Token 还有效问题的解决还是比较容易的,说一种我觉得比较好的方式:**使用用户的密码的哈希值对 Token 进行签名。因此,如果密码更改,则任何先前的令牌将自动无法验证。**
**1、将 JWT 存入内存数据库**
### Token 的续签问题
将 JWT 存入 DB 中Redis 内存数据库在这里是不错的选择。如果需要让某个 JWT 失效就直接从 Redis 中删除这个 JWT 即可。但是,这样会导致每次使用 JWT 发送请求都要先从 DB 中查询 JWT 是否存在的步骤,而且违背了 JWT 的无状态原则。
Token 有效期一般都建议设置的不太长,那么 Token 过期后如何认证,如何实现动态刷新 Token避免用户经常需要重新登录
**2、黑名单机制**
我们先来看看在 Session 认证中一般的做法:**假如 session 的有效期30分钟如果 30 分钟内用户有访问,就把 session 有效期延长30分钟。**
和上面的方式类似,使用内存数据库比如 Redis 维护一个黑名单,如果想让某个 JWT 失效的话就直接将这个 JWT 加入到 **黑名单** 即可。然后,每次使用 JWT 进行请求的话都会先判断这个 JWT 是否存在于黑名单中。
- **类似于 Session 认证中的做法**:这种方案满足于大部分场景。假设服务端给的 Token 有效期设置为30分钟服务端每次进行校验时如果发现 Token 的有效期马上快过期了,服务端就重新生成 Token 给客户端。客户端每次请求都检查新旧Token如果不一致则更新本地的Token。这种做法的问题是仅仅在快过期的时候请求才会更新 Token ,对客户端不是很友好。
- **每次请求都返回新 Token** :这种方案的的思路很简单,但是,很明显,开销会比较大。
- **Token 有效期设置到半夜** :这种方案是一种折衷的方案,保证了大部分用户白天可以正常登录,适用于对安全性要求不高的系统。
- **用户登录返回两个 Token** :第一个是 accessToken ,它的过期时间 Token 本身的过期时间比如半个小时,另外一个是 refreshToken 它的过期时间更长一点比如为1天。客户端登录后将 accessToken和refreshToken 保存在本地,每次访问将 accessToken 传给服务端。服务端校验 accessToken 的有效性,如果过期的话,就将 refreshToken 传给服务端。如果有效,服务端就生成新的 accessToken 给客户端。否则客户端就重新登录即可。该方案的不足是1) 需要客户端来配合2) 用户注销的时候需要同时保证两个 Token 都无效3) 重新请求获取 Token 的过程中会有短暂 Token 不可用的情况可以通过在客户端设置定时器当accessToken 快过期的时候,提前去通过 refreshToken 获取新的accessToken
前两种方案的核心在于将有效的 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 最适合的场景是不需要服务端保存用户状态的场景,如果考虑到 Token 注销和 Token 续签的场景话,没有特别好的解决方案,大部分解决方案都给 Token 加上了状态,这就有点类似 Session 认证了。
JWT 其中一个很重要的优势是无状态,但实际上,我们想要在实际项目中合理使用 JWT 的话,也还是需要保存 JWT 信息
## 参考
JWT 也不是银弹,也有很多缺陷,具体是选择 JWT 还是 Session 方案还是要看项目的具体需求。万万不可尬吹 JWT而看不起其他身份认证方案。
另外,不用 JWT 直接使用普通的 Token(随机生成,不包含具体的信息) 结合 Redis 来做身份认证也是可以的。我在 [「优质开源项目推荐」](https://javaguide.cn/open-source-project/)第 8 期推荐过的 [Sa-Token](https://github.com/dromara/sa-JWT) 这个项目是一个比较完善的 基于 JWT 的身份认证解决方案,支持自动续签、踢人下线、账号封禁、同端互斥登录等功能,感兴趣的朋友可以看看。
![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/javaguide/system-design/jwt/image-20220609170714725.png)
## 参考
- JWT 超详细分析https://learnku.com/articles/17883
- How to log out when using JWThttps://medium.com/devgorilla/how-to-log-out-when-using-jwt-a8c7823e8a6
- CSRF protection with JSON Web Tokenshttps://medium.com/@agungsantoso/csrf-protection-with-json-web-Tokens-83e0f2fcbcc
- Invalidating JSON Web Tokenshttps://stackoverflow.com/questions/21978658/invalidating-json-web-Tokens
- CSRF protection with JSON Web JWTshttps://medium.com/@agungsantoso/csrf-protection-with-json-web-JWTs-83e0f2fcbcc
- Invalidating JSON Web JWTshttps://stackoverflow.com/questions/21978658/invalidating-json-web-JWTs

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@ -9,11 +9,11 @@ tag:
JWT JSON Web Token 是目前最流行的跨域认证解决方案,是一种基于 Token 的认证授权机制。 从 JWT 的全称可以看出JWT 本身也是 Token一种规范化之后的 JSON 结构的 Token。
Token 自身包含了身份验证所需要的所有信息,因此,我们的服务器不需要存储 Session 信息。这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
JWT 自身包含了身份验证所需要的所有信息,因此,我们的服务器不需要存储 Session 信息。这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
可以看出,**JWT 更符合设计 RESTful API 时的「Stateless无状态」原则** 。
并且, 使用 Token 认证可以有效避免 CSRF 攻击,因为 Token 一般是存在在 localStorage 中,使用 JWT 进行身份验证的过程中是不会涉及到 Cookie 的。
并且, 使用 JWT 认证可以有效避免 CSRF 攻击,因为 JWT 一般是存在在 localStorage 中,使用 JWT 进行身份验证的过程中是不会涉及到 Cookie 的。
我在 [JWT 优缺点分析](./advantages&disadvantages-of-jwt.md)这篇文章中有详细介绍到使用 JWT 做身份认证的优势和劣势。
@ -23,6 +23,8 @@ Token 自身包含了身份验证所需要的所有信息,因此,我们的
## JWT 由哪些部分组成?
![此图片来源于https://supertokens.com/blog/oauth-vs-jwt](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/javaguide/system-design/jwt/jwt-composition.png)
JWT 本质上就是一组字串,通过(`.`)切分成三个为 Base64 编码的部分:
- **Header** : 描述 JWT 的元数据,定义了生成签名的算法以及 `Token` 的类型。
@ -43,7 +45,7 @@ SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header 和 Payload 都是 JSON 格式的数据Signature 由 Payload、Header 和 Secret(密钥)通过特定的计算公式和加密算法得到。
![](./images/basis-of-authority-certification/jwt.io.png)
![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/javaguide/system-design/jwt/jwt.io.png)
### Header
@ -102,7 +104,7 @@ JSON 形式的 Payload 被转换成 Base64 编码,成为 JWT 的第二部分
### Signature
Signature 部分是对前两部分的签名,作用是防止 Token(主要是 payload 被篡改。
Signature 部分是对前两部分的签名,作用是防止 JWT主要是 payload 被篡改。
这个签名的生成需要用到:
@ -119,33 +121,33 @@ HMACSHA256(
secret)
```
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"`.`)分隔,成为 JWT 的第三部分
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"`.`)分隔,这个字符串就是 JWT
## 如何基于 JWT 进行身份验证?
在基于 Token 进行身份验证的的应用程序中,服务器通过 Payload、Header 和 `Secret`(密钥)创建`Token`(令牌)并将 `Token` 发送给客户端。客户端接收到 `Token` 之后,会将其保存在 Cookie 或者 localStorage 里面,以后客户端发出的所有请求都会携带这个令牌。
在基于 JWT 进行身份验证的的应用程序中,服务器通过 Payload、Header 和 Secret(密钥)创建 JWT 并将 JWT 发送给客户端。客户端接收到 JWT 之后,会将其保存在 Cookie 或者 localStorage 里面,以后客户端发出的所有请求都会携带这个令牌。
![jwt](./images/basis-of-authority-certification/jwt.png)
简化后的步骤如下:
1. 用户向服务器发送用户名、密码以及验证码用于登陆系统。
2. 如果用户用户名、密码以及验证码校验正确的话,服务端会返回已经签名的 `Token`
3. 用户以后每次向后端发请求都在 Header 中带上这个 `Token`
4. 服务端检查 `Token` 并从中获取用户相关信息。
2. 如果用户用户名、密码以及验证码校验正确的话,服务端会返回已经签名的 Token也就是 JWT
3. 用户以后每次向后端发请求都在 Header 中带上这个 JWT
4. 服务端检查 JWT 并从中获取用户相关信息。
两点建议:
1. 建议将 `Token` 存放在 localStorage 中,放在 Cookie 中会有 CSRF 风险。
2. 请求服务端并携带 Token 的常见做法是将 `Token` 放在 HTTP Header 的 `Authorization` 字段中(`Authorization: Bearer Token`)。
1. 建议将 JWT 存放在 localStorage 中,放在 Cookie 中会有 CSRF 风险。
2. 请求服务端并携带 JWT 的常见做法是将其放在 HTTP Header 的 `Authorization` 字段中(`Authorization: Bearer Token`)。
**[spring-security-jwt-guide](https://github.com/Snailclimb/spring-security-jwt-guide)** 就是一个基于 JWT 来做身份认证的简单案例,感兴趣的可以看看。
## JWT 如何防止 Token 被篡改?
## 如何防止 JWT 被篡改?
有了签名之后,即使 Token 被泄露或者解惑,黑客也没办法同时篡改 Signature 、Header 、Payload。
有了签名之后,即使 JWT 被泄露或者解惑,黑客也没办法同时篡改 Signature 、Header 、Payload。
这是为什么呢?因为服务端拿到 Token 之后,会解析出其中包含的 Header、Payload 以及 Signature 。服务端会根据 Header、Payload、密钥再次生成一个 Signature。拿新生成的 Signature 和 Token 中的 Signature 作对比,如果一样就说明 Header 和 Payload 没有被修改。
这是为什么呢?因为服务端拿到 JWT 之后,会解析出其中包含的 Header、Payload 以及 Signature 。服务端会根据 Header、Payload、密钥再次生成一个 Signature。拿新生成的 Signature 和 JWT 中的 Signature 作对比,如果一样就说明 Header 和 Payload 没有被修改。
不过,如果服务端的秘钥也被泄露的话,黑客就可以同时篡改 Signature 、Header 、Payload 了。黑客直接修改了 Header 和 Payload 之后,再重新生成一个 Signature 就可以了。
@ -155,7 +157,7 @@ HMACSHA256(
1. 使用安全系数高的加密算法。
2. 使用成熟的开源库,没必要造轮子。
3. Token 存放在 localStorage 中而不是 Cookie 中,避免 CSRF 风险。
3. JWT 存放在 localStorage 中而不是 Cookie 中,避免 CSRF 风险。
4. 一定不要将隐私信息存放在 Payload 当中。
5. 密钥一定保管好一定不要泄露出去。JWT 安全的核心在于签名,签名安全的核心在密钥。
6. Payload 要加入 `exp` JWT 的过期时间),永久有效的 JWT 不合理。并且JWT 的过期时间不易过长。