日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網(wǎng)站首頁 編程語言 正文

jwt Claims token 秘鑰稍有不同也能解析成功 signWith setSigningKey

作者:阿亮_1024 更新時間: 2022-02-27 編程語言

問題描述

使用io.jsonwebtoken.Jwts構造了一個token,在解析這個token時,發(fā)現(xiàn)解析秘鑰和構建秘鑰不完全相同也可以成功解析,代碼如下

簽發(fā)token

    /** 測試生成token */
    @Test
    public void testJwt() {
        JwtBuilder jwtBuilder = Jwts.builder()
                // 唯一ID {"":""}
                .setId("888")
                // 接受的用戶 {"sub":"Rose"}
                .setSubject("Rose")
                // 簽發(fā)時間 {"iat":"。。。"}
                .setIssuedAt(new Date())
                // 簽名算法 及秘鑰
                .signWith(SignatureAlgorithm.HS256, "xxxx");
        // 簽發(fā)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()
                // 解析時的秘鑰一定要和簽發(fā)時秘鑰相同,但是發(fā)現(xiàn)這了的秘鑰為4-7個x都是可以成功解析的
                .setSigningKey("xxxx")
                // .parse(token)
                .parseClaimsJws(token)
                .getBody();
        System.out.println(claims);
    }

在簽發(fā)時我的秘鑰是四個x,但是在解析時,4-7個x都能成功解析,我很不理解,雖然不是什么秘鑰都可以成功解析,但是近似的就能解析也太不安全了吧

問題分析

我第一時間想到的是去網(wǎng)上查,沒有想到第一時間自己看源碼,因為可能源碼一時半會看不出來個啥。去網(wǎng)上查了一下,果然查到了一些有用的東西,然后我點進源碼看了一下,一下子就清楚了。

先查看設置秘鑰的地方,io.jsonwebtoken.JwtBuilder有一個默認的實現(xiàn)類io.jsonwebtoken.impl.DefaultJwtBuilder,我們看看他的signWith方法,signWith有三個重載形式,我們只看我們調用的那個就行了
signWith方法
關鍵的地方我標出來了,signWith拿到秘鑰之后是先將秘鑰用base64解碼之后再進行操作的。

然后再看解析token時的地方,io.jsonwebtoken.JwtParser也有一個默認的實現(xiàn)類io.jsonwebtoken.impl.DefaultJwtParser,設置秘鑰的方法setSigningKey也有三個重載形式,我們使用的是下面這個
setSigningKey方法
可以看到,setSigningKey方法也將拿到的秘鑰用base64解碼了,咋一看好像沒什么問題,解碼就解碼唄,反正兩邊都解了,同一個字符串,解碼過肯定是一樣的結果,但問題恰巧就出現(xiàn)在這里。

雖然相同的字符串經(jīng)過base64解碼過后也一定是相同的,但是不同的字符串經(jīng)過base64解碼過后也可能是相同的!!

下面是我的測試
base64測試
可以看到,我測試了三種不同地方的工具類,在將xxxx和xxxxx按照base64解碼時,都解碼成相同的byte數(shù)組了。在jwt設置秘鑰和解析秘鑰時,使用的是第一種,所以就不難理解,為啥秘鑰即便不完全相同,只要近似也能解析。

解決問題

雖然搞清楚了原理,那怎么解決這個問題呢?或者這是jjwt的一個或base64的bug?是不是base64的bug我不知道,但是一定不是jjwt的bug,只是我們調用api是沒有按照人家要求調用。再來看看構建token時設置秘鑰的方法
方法描述
人家方法的變量名叫:base64EncodedSecretKey,就是想讓你傳一個經(jīng)過base64編碼過后的字符串。接口上也有明確的注釋:
接口注釋
在解析token時設置秘鑰的方法也有同樣的注釋。如果按照api要求來調用,就沒有問題了,因為base64是對稱加密的,解碼被加密過后一樣的字符串,得到的肯定是兩個一樣原始內(nèi)容。

反思總結

在調用api時,沒有好好的看別人的文檔或是注釋,記大過一次。

聯(lián)想拓展

我對base64了解沒那么深,只知道是一個對稱加密的算法,但是也會感到奇怪,為什么對不同的字符串進行解碼時,能得到相同的結果呢?

我只能嘗試這么理解:Base64在加密時,是通過一步一步加密的,相同的東西,在加密時經(jīng)過的步驟都是相同的,所以最終加密出來也是相同的。但是解密則有點不同,什么不同呢?如果你是經(jīng)過我Base64加密過后,你再來經(jīng)過我解密,我能按照加密過程的逆過程,一步一步把你還原成原來的樣子。但是如果你壓根就沒有經(jīng)過我Base64加密,你卻要來走我Base64的還原過程,那我在還原的過程中,有的步驟都沒法走,直接跳過了,最后把你“還原”。所以那些近似的、不是經(jīng)過Base64加密的字符串,在經(jīng)過Base64解密時,都有一些相同步驟跳過了,所以最終解密過后得到了相同的東西。當然,這都是我自己的理解。

另外,在測試過程中,我發(fā)現(xiàn),有的地方的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是相同的,但是第三者解密出來是不同的,不知道這是為啥。

文章參考:如果SigningKey稍有不同,JJWT解析不會失敗

原文鏈接:https://blog.csdn.net/ql_7256/article/details/120522555

欄目分類
最近更新