注意!侵入JSON Web Token(JWT)

2021-01-13 讀芯術

全文共4545字,預計學習時長13分鐘

圖源:Unsplash

想像一下,你正安逸地躺在家裡刷公眾號,突然,你的手機嘀嘀嘀,一筆又一筆巨款從你的卡裡不翼而飛,急得你驚起直跺腳,咋回事啊?!

突然你想到了剛剛在「讀芯術」看到的有關「JSON Web Token」的文章。

你恍然大悟,哦~原來是有人偽造token來冒充自己登錄銀行網站取款呀,原來如此。

弄明白,安心了……個鬼,趕緊報警啊。

接下來,小芯就帶你看看這篇JWT的文章,共同探討使用JWT(和一般的基於籤名的token)的安全隱患,以及攻擊者利用這些隱患繞過訪問控制的方法。

是JSONWeb Token?

有問必答:JSON Web Token是一種在商業應用程式中廣泛使用的訪問token。它基於JSON格式,並包含一個籤名以確保token的完整性。

JWT的運行機制是什麼?

JWT由三部分構成:頭部(header),載荷(payload)和籤名(signature)。

頭部

JWT的頭部聲明了籤名算法。下面這段代碼就是一個JSON blob對象的base64url編碼字符串的頭部:

{

"alg" :"HS256",

"typ" : "JWT"

}base64url encoded string: eyBhbGcgOiBIUzI1NiwgdHlwIDogSldUIH0K

(Base64url編碼是base64編碼在URL格式上的修改版本。它同base64十分類似,但它使用了不同的符號字符並省略了填充。)

JWT最常用的算法是HMAC(Hash-based Message Authentication Code,哈希運算消息認證碼)和RSA(一種非對稱加密算法)。

載荷

載荷包含了用於訪問控制的信息。該部分在用於生成token前也使用base64url進行編碼。

{

"user_name" :"admin",

}base64url encoded string: eyB1c2VyX25hbWUgOiBhZG1pbiB9Cg

籤名

籤名用於驗證token是否被篡改。其計算方法是:先將編碼後的頭部與載荷串聯在一起,再使用頭部聲明的算法來籤名。

signature= HMAC-SHA256(base64urlEncode(header) + '.' + base64urlEncode(payload),secret_key)// Let's just say the value of secret_key is "key".->signature function returns 4Hb/6ibbViPOzq9SJflsNGPWSk6B8F6EqVrkNjpXh7M

這個token使用密鑰為「key」的HS256算法為字符串「eyBhbGcgOiBIUzI1NiwgdHlwIDogSldUIH0K.eyB1c2VyX25hbWUgOiBhZG1pbiB9Cg」籤名。編碼後得到字符串「4Hb /6ibbViPOzq9SJflsNGPWSk6B8F6EqVrkNjpXh7M」。

完整的token

將頭部、載荷和籤名用「.」連接起來可以構成一個完整的token。如下所示:

eyBhbGcgOiBIUzI1NiwgdHlwIDogSldUIH0K.

eyB1c2VyX25hbWUgOiBhZG1pbiB9Cg.

4Hb/ 6ibbViPOzq9SJflsNGPWSk6B8F6EqVrkNjpXh7M

圖源:Unsplash

如何繞過JWT訪問控制

正常情況下,由於無法篡改JWT載荷的數據,它能提供一種安全途徑來標識用戶(由於用戶無權訪問密鑰,她便無法在token上簽名。)

然而,若JWT出現異常,攻擊者可以通過多種方式繞過其安全機制來偽造token。

更改算法類型

攻擊者偽造token的方法之一是篡改頭部的alg欄位。如果應用程式不限制JWT使用的算法類型,攻擊者可能會通過指定算法破壞token的安全性。

1. 不使用加密算法

JWT支持將算法設定為「None」。如果「alg」欄位設為「 None」,那麼籤名會被置空,這樣任何token都是有效的。例如:

eyAiYWxnIiA6ICJOb25lIiwgInR5cCIgOiAiSldUIiB9Cg.

eyB1c2VyX25hbWUgOiBhZG1pbiB9Cg.

這個token只是下面這兩個blob對象用base64url編碼後得出的值,它並沒有提供籤名。

{

「 alg」:「None」,

「typ」:「 JWT」

}{

「user」:「admin」

}

設定該功能的最初目的是為了方便調試。但是,若不在生產環境中關閉該功能,攻擊者可以通過將alg欄位設置為「None」來偽造他們想要的任何token,接著便可以使用偽造的token冒充任意用戶登陸網站。

2. HMAC算法

JWT兩種最常用的算法是HMAC和RSA。HMAC用同一個密鑰對token進行籤名和認證。而RSA需要兩個密鑰,先用私鑰加密創建token,然後使用其對應的公鑰來認證。

HMAC->

signed with a key, verified with the same keyRSA ->

signed with aprivate key,

verified with the corresponding public key

注意,要保護好HMAC的密鑰和RSA私鑰信息,因為它們都是給token籤名的。

現在,假設有一個用RSA籤名的應用程式。這些token用對公眾保密的私鑰A籤名。再使用任何人都能獲取的公鑰B來驗證。只要不改變該token的算法,這個token就是有效的。

Token signed with key A -> Token verified with key B (RSA scenario)

但是,如果攻擊者把算法改為HMAC,他便能利用原RSA下的公鑰B來籤名偽造token,而這種做法生成的token同樣有效。

這是因為一開始用RSA給token籤名時,應用程式會使用公鑰B來認證用戶身份。當算法更改為HMAC時,仍使用RSA的公鑰B認證,但這次,公鑰B也可以用於籤名了(因為HMAC是對稱性加密算法)。

Token signed with key B -> Token verified with key B (HMAC scenario)

提供無效籤名

到達應用程式後,token籤名可能永遠不會被認證。這樣,攻擊者便可以通過提供無效籤名簡單地繞過安全機制。

暴力破解密鑰

攻擊者也可以暴力破解用於籤名的JWT密鑰。

第一步,攻擊者要掌握一些信息:用於token籤名的算法、加密後的載荷及最終得到的加密字符串。若密鑰不夠複雜,攻擊者可能可以輕易地暴力破解它。

洩漏密鑰

假設攻擊者無法暴力破解密鑰,他可能會想辦法讓密鑰洩露出來。若攻擊者利用文檔漏洞(如目錄遍歷,XXE和SSRF漏洞)讀取儲存了密鑰值的文檔,他便能竊取密鑰從而給任意token籤名。

操縱KID

KID指的是「密鑰序號」(Key ID)。它是JWT頭部的一個可選欄位,開發人員可以用它標識認證token的某一密鑰。KID參數的正確用法如下所示:

{

"alg": "HS256",

"typ": "JWT",

"kid": "1" // use key number 1 to verify the token

}

由於該欄位由用戶控制,因此攻擊者可能會操縱它,這會引發危險後果。

圖源:Unsplash

1. 目錄遍歷

由於KID通常用於從文件系統中檢索密鑰文件,因此,如果在使用前不清理KID,文件系統可能會遭到目錄遍歷攻擊。這樣,攻擊者便能夠在文件系統中指定任意文件作為認證的密鑰。

「kid」: 「../../public/css/main.css」// use the publicly available file main.css to verify the token

例如,攻擊者可以強行設定應用程式使用公開可用文件作為密鑰,並用該文件給HMAC加密的token籤名。

2. SQL注入

KID也可以用於在資料庫中檢索密鑰。在該情況下,攻擊者很可能會利用SQL注入來繞過JWT安全機制。

如果可以在KID參數上進行SQL注入,攻擊者便能使用該注入返回任意值。

「kid」:"aaaaaaa' UNION SELECT 'key';--"// use the string "key" toverify the token

上面這個注入會導致應用程式返回字符串「 key」(因為資料庫中不存在名為「 aaaaaaa」的密鑰)。然後使用字符串「 key」作為密鑰來認證token。

操縱頭部參數

除KID外,JWT標準還能讓開發人員通過URL指定密鑰。

1. JKU頭部參數

JKU全稱是「JWKSet URL」,它是頭部的一個可選欄位,用於指定連結到一組加密token密鑰的URL。若允許使用該欄位且不設置限定條件,攻擊者就能託管自己的密鑰文件,並指定應用程式,用它來認證token。

jku URL -> file containing JWK set -> JWK used to verify the token

2. JWK頭部參數

頭部可選參數JWK(JSON Web Key)使得攻擊者能將認證的密鑰直接嵌入token中。

3. 操縱X5U,X5C URL

同JKU或JWK頭部類似,X5U和X5C頭部參數讓攻擊者能夠指定認證的公鑰證書或證書鏈。X5U以URI形式指定信息,而X5C允許將證書值嵌入token中。

其他安全隱患

若JWT安全機制不能正常運行,還會產生其他安全隱患。這些問題不常見,但絕對值得關注:

信息洩漏

由於JWT用於訪問控制,因此它通常包含用戶的相關信息。

如果不加密token,則任何人都能通過base64解碼並讀取token上的載荷信息。因此,如果token包含敏感信息,它便可能成為信息洩漏的來源。正常的token籤名僅保障數據完整性,而非機密性。

命令注入

有時,將KID參數直接傳到不安全的文件讀取操作可能會讓一些命令注入代碼流中。

一些函數就能給此類型攻擊可乘之機,比如Ruby open()。攻擊者只需在輸入的KID文件名後面添加命令,即可執行系統命令:

「key_file」 | whoami;

類似情況還有很多,這只是其中一個例子。理論上,每當應用程式將未審查的頭部文件參數傳遞給類似system(),exec()的函數時,都會產生此種漏洞。

本質上,JWT僅僅是另一種用戶輸入的形式。程序開發者應謹慎使用JWT並對其進行嚴格審查。

免責聲明:這篇文章是為了引起人們對JWT安全漏洞的關注,並幫助開發人員認識到常見的陷阱。請不要使用這些信息來攻擊網站或冒充他人身份哦。

在您沒有測試權限的系統上嘗試此操作是非法的。如果您發現了安全漏洞,請務必向供應商披露,以營造一個更為安全的網際網路環境。大家都是好孩子~

留言點讚關注

我們一起分享AI學習與發展的乾貨

如轉載,請後臺留言,遵守轉載規範

相關焦點

  • (建議收藏)|Spring Boot集成JSON Web Token(JWT)
    // 該token籤發給1234567890,姓名為John Doe(自定義的欄位),籤發時間為1516239022var payload = Base64URL( {"sub": "1234567890", "name": "John Doe", "iat": 1516239022})注意,JWT中payload是不加密的,只是Base64URL編碼一下,任何人拿到都可以進行解碼
  • Json Web Token(JWT)的使用
    什麼場景使用JSON Web TokensAuthorization:這個是最常用的場景,當用戶登錄後,服務端返回一個token,客戶端攜帶這個token就可以訪問token許可資源。Information Exchange:使用JWT可以在多個系統進行系統交換,因為JWT可以被加密。JWT的結構JWT的結構有以下三部分組成,用句號(.)分割。
  • 入門|egg.js 入門之egg-jwt
    ) => { const { controller, router, jwt } = app; //正常路由 router.post('/admin/login', controller.admin.login); /* * 這裡的第二個對象不再是控制器,而是 jwt 驗證對象,第三個地方才是控制器 * 只有在需要驗證 token 的路由才需要第二個 是 jwt 否則第二個對象為控制器
  • SpringSecurity + JWT前後端分離架構實現
    --Token生成與解析--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency
  • SpringSecurity代碼實現JWT接口權限授予與校驗
    圖片:開發JWT工具類上面的代碼就是使用io.jsonwebtoken.jjwt提供的方法開發JWT令牌生成、刷新的工具類。並將"/authentication"和 "/refreshtoken" 開放訪問權限,如何開放訪問權限,我們之前的文章已經講過了。
  • JWT 使用 nimbus-jose-jwt 進行解碼
    常用的可以使用 OAuth0 提供的解碼包,你也可能會使用 nimbus-jose-jwt 包。Maven 配置參數為:<dependency><groupId>com.nimbusds</groupId><artifactId>nimbus-jose-jwt</artifactId><version>9.0.1</version>
  • 利用jwt 可以獲取用戶的額外信息?
    涉及的小問題有以下三個:如何在返回的 jwt 中添加自定義數據;如何在 jwt 中添加用戶的額外數據,比如用戶 id、手機號碼;如何在資源伺服器中取出這些自定義數據。下面我們分別來看如何實現。如何在返回的 jwt 中添加自定義數據這個問題比較簡單,只要按照如下兩步即可:1.
  • Spring Security OAuth2.0認證授權五:用戶信息擴展到jwt
    令牌的時候就只存放了這麼多信息,我們到jwt.io網站上貼出jwt令牌查看下payload中內容就就知道有什麼內容了:本篇文章的目的就是為了解決該問題,把用戶信息(用戶名、頭像、手機號、郵箱等)放到jwt token中,經過網關解析之後攜帶用戶信息訪問目標服務,目標服務將用戶信息保存到上下文並保證線程安全性的情況下封裝成工具類提供給各種環境下使用。
  • 就能學會以太坊 JSON API 基礎知識!
    作者 | Nicolas Schapeler責編 | Carol出品 | 區塊鏈大本營(ID:blockchain_camp)前幾天,作者遇到了這樣一種情況,需要在一個讓web3.py幾乎不可能工作的環境中使用Python與Ethereum網絡進行通信。
  • JWT:你好了解一下 只要兩分鐘!
    看起來很唬人的樣子,不能查,一查就是個token生成方式。好,那就來了解一下吧。什麼是JWTJSON Web Token (JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,該token被設計為緊湊且安全的,特別適用於分布式站點的單點登錄(SSO)場景。
  • Springmvc框架對json的支持 Java程式設計師必看
    json是一種前後端分離思想所使用的存儲數據的格式,然而使用Springmvc這個框架在對前臺參數處理時會遇到很多坑,下面我們就模擬一下前臺發送json數據看springmvc能否成功接收。路徑當做請求處理了,於是我們必須不讓他處理這個請求,讓它對靜態資源放行需要進行如下配置在web.xml中我們添加幾條通過名為default的servlet處理的url-pattern,分別對應js和css文件。
  • api框架 web 最好的go_golang api框架 - CSDN
    其實對於golang而言,web框架的依賴要遠比Python,Java之類的要小。自身的net/http足夠簡單,性能也非常不錯。框架更像是一些常用函數或者工具的集合。藉助框架開發,不僅可以省去很多常用的封裝帶來的時間,也有助於團隊的編碼風格和形成規範。下面就Gin的用法做一個簡單的介紹。
  • 一分鐘簡單了解JSON Web Token
    aud: 接收該JWT的一方exp(expires): 什麼時候過期,這裡是一個Unix時間戳iat(issued at): 在什麼時候籤發的除了標準定義中的欄位外,我們還可以自定義欄位,比如在 JWT 中,我們的載荷信息可能如下:{ "sub": "1234567890", "name": "pingtouge", "admin": true}我們需要注意
  • JSON對象和簡單練習
    1環境搭建在使用JSON對象之前,我們需要提前下載幾個jar包,拷貝到java web工程下的\WEB-INF\lib\路徑下以下這幾個jar包可以到maven倉庫下載,我這裡也貼出來了這幾個下載地址。
  • 全棧AI工程師指南,DIY一個識別手寫數字的web應用
    ,並且可以利用web的任何交互方式。= model.to_json() open('my_model_architecture.json','w').write(json_string) model.save_weights('my_model_weights.h5') 第二篇
  • 用Scala實現簡單的Web和API伺服器
    我們將使用Cask web框架:http://www.lihaoyi.com/cask/Cask是一個Scala的HTTP為框架,可以用來架設簡單的網站並迅速運行。())+ .then(json => {+ if (json.success) {+ messageList.innerHTML = json.txt+ msgInput.value