網站首頁 編程語言 正文
問題描述
使用io.jsonwebtoken.Jwts構造了一個token,在解析這個token時,發現解析秘鑰和構建秘鑰不完全相同也可以成功解析,代碼如下
簽發token
/** 測試生成token */
@Test
public void testJwt() {
JwtBuilder jwtBuilder = Jwts.builder()
// 唯一ID {"":""}
.setId("888")
// 接受的用戶 {"sub":"Rose"}
.setSubject("Rose")
// 簽發時間 {"iat":"。。。"}
.setIssuedAt(new Date())
// 簽名算法 及秘鑰
.signWith(SignatureAlgorithm.HS256, "xxxx");
// 簽發token
String token = jwtBuilder.compact();
System.out.println(token);
String[] split = token.split("\\.");
// 頭部
System.out.println(Base64Codec.BASE64.decodeToString(split[0]));
// 載荷
System.out.println(Base64Codec.BASE64.decodeToString(split[1]));
// 算法及秘鑰 這個會亂碼
System.out.println(Base64Codec.BASE64.decodeToString(split[2]));
}
解析token
/** 解析token */
@Test
public void testParseToken() {
String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjMyNzMxMzYyfQ.9GZJUoTNwJuMh5tFMd3giJh36YNuCnFuWsDKONOg2C8";
// 得到的是荷載
Claims claims = (Claims) Jwts.parser()
// 解析時的秘鑰一定要和簽發時秘鑰相同,但是發現這了的秘鑰為4-7個x都是可以成功解析的
.setSigningKey("xxxx")
// .parse(token)
.parseClaimsJws(token)
.getBody();
System.out.println(claims);
}
在簽發時我的秘鑰是四個x,但是在解析時,4-7個x都能成功解析,我很不理解,雖然不是什么秘鑰都可以成功解析,但是近似的就能解析也太不安全了吧
問題分析
我第一時間想到的是去網上查,沒有想到第一時間自己看源碼,因為可能源碼一時半會看不出來個啥。去網上查了一下,果然查到了一些有用的東西,然后我點進源碼看了一下,一下子就清楚了。
先查看設置秘鑰的地方,io.jsonwebtoken.JwtBuilder有一個默認的實現類io.jsonwebtoken.impl.DefaultJwtBuilder,我們看看他的signWith方法,signWith有三個重載形式,我們只看我們調用的那個就行了
關鍵的地方我標出來了,signWith拿到秘鑰之后是先將秘鑰用base64解碼之后再進行操作的。
然后再看解析token時的地方,io.jsonwebtoken.JwtParser也有一個默認的實現類io.jsonwebtoken.impl.DefaultJwtParser,設置秘鑰的方法setSigningKey也有三個重載形式,我們使用的是下面這個
可以看到,setSigningKey方法也將拿到的秘鑰用base64解碼了,咋一看好像沒什么問題,解碼就解碼唄,反正兩邊都解了,同一個字符串,解碼過肯定是一樣的結果,但問題恰巧就出現在這里。
雖然相同的字符串經過base64解碼過后也一定是相同的,但是不同的字符串經過base64解碼過后也可能是相同的!!
下面是我的測試
可以看到,我測試了三種不同地方的工具類,在將xxxx和xxxxx按照base64解碼時,都解碼成相同的byte數組了。在jwt設置秘鑰和解析秘鑰時,使用的是第一種,所以就不難理解,為啥秘鑰即便不完全相同,只要近似也能解析。
解決問題
雖然搞清楚了原理,那怎么解決這個問題呢?或者這是jjwt的一個或base64的bug?是不是base64的bug我不知道,但是一定不是jjwt的bug,只是我們調用api是沒有按照人家要求調用。再來看看構建token時設置秘鑰的方法
人家方法的變量名叫:base64EncodedSecretKey,就是想讓你傳一個經過base64編碼過后的字符串。接口上也有明確的注釋:
在解析token時設置秘鑰的方法也有同樣的注釋。如果按照api要求來調用,就沒有問題了,因為base64是對稱加密的,解碼被加密過后一樣的字符串,得到的肯定是兩個一樣原始內容。
反思總結
在調用api時,沒有好好的看別人的文檔或是注釋,記大過一次。
聯想拓展
我對base64了解沒那么深,只知道是一個對稱加密的算法,但是也會感到奇怪,為什么對不同的字符串進行解碼時,能得到相同的結果呢?
我只能嘗試這么理解:Base64在加密時,是通過一步一步加密的,相同的東西,在加密時經過的步驟都是相同的,所以最終加密出來也是相同的。但是解密則有點不同,什么不同呢?如果你是經過我Base64加密過后,你再來經過我解密,我能按照加密過程的逆過程,一步一步把你還原成原來的樣子。但是如果你壓根就沒有經過我Base64加密,你卻要來走我Base64的還原過程,那我在還原的過程中,有的步驟都沒法走,直接跳過了,最后把你“還原”。所以那些近似的、不是經過Base64加密的字符串,在經過Base64解密時,都有一些相同步驟跳過了,所以最終解密過后得到了相同的東西。當然,這都是我自己的理解。
另外,在測試過程中,我發現,有的地方的Base64工具類,測試的結果不一樣,上面測試了三個base64解碼,分別是:
- io.jsonwebtoken.impl.TextCodec.BASE64
- io.jsonwebtoken.impl.Base64Codec
- cn.hutool.core.codec.Base64
三者在解密五個x時,結果都是一樣的,也都和4個x的解密相同。但是在解密6個x和7個x時,就有所不同了
前兩者解密6個x和7個x時,得到的結果依然和4個x是相同的,但是第三者解密出來是不同的,不知道這是為啥。
原文鏈接:https://blog.csdn.net/ql_7256/article/details/120522555
相關推薦
- 2022-11-14 mq消息積壓怎么對應
- 2022-05-29 解決Docker容器下不能使用vim命令的問題_docker
- 2022-08-03 利用Python連接Oracle數據庫的基本操作指南_python
- 2022-04-12 Top-level statements must precede namespace and ty
- 2023-06-04 Pandas.DataFrame重置列的行名實現(set_index)_python
- 2022-03-03 sublime-text - Sublime Text 3,在注釋的下一行,如何取消自動注釋?
- 2022-10-11 React - 判斷焦點是否在某個元素上
- 2022-11-13 Python中tqdm的使用和例子_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支