您好,登錄后才能下訂單哦!
這篇文章主要講解了“什么是JWT”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“什么是JWT”吧!
JSON WEB Token(JWT,讀作 [/d??t/]),是一種基于JSON的、用于在網絡上聲明某種主張的令牌(token)。JWT通常由三部分組成: 頭信息(header), 消息體(payload)和簽名(signature)。
頭信息指定了該JWT使用的簽名算法:
header = '{"alg":"HS256","typ":"JWT"}'
HS256
表示使用了 HMAC-SHA256 來生成簽名。
消息體包含了JWT的意圖:
payload = '{"loggedInAs":"admin","iat":1422779638}'//iat表示令牌生成的時間
未簽名的令牌由base64url
編碼的頭信息和消息體拼接而成(使用"."分隔),簽名則通過私有的key計算而成:
key = 'secretkey' unsignedToken = encodeBase64(header) + '.' + encodeBase64(payload) signature = HMAC-SHA256(key, unsignedToken)
最后在未簽名的令牌尾部拼接上base64url
編碼的簽名(同樣使用"."分隔)就是JWT了:
token = encodeBase64(header) + '.' + encodeBase64(payload) + '.' + encodeBase64(signature) # token看起來像這樣: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN_oWnFSRgCzcmJmMjLiuyu5CSpyHI
JWT常常被用作保護服務端的資源(resource),客戶端通常將JWT通過HTTP的Authorization
header發送給服務端,服務端使用自己保存的key計算、驗證簽名以判斷該JWT是否可信:
Authorization: Bearer eyJhbGci*...<snip>...*yu5CSpyHI
近年來RESTful API開始風靡,使用HTTP header來傳遞認證令牌似乎變得理所應當,而單頁應用(SPA)、前后端分離架構似乎正在促成越來越多的WEB應用放棄歷史悠久的cookie-session認證機制,轉而使用JWT來管理用戶session。支持該方案的人認為:
在cookie-session方案中,cookie內僅包含一個session標識符,而諸如用戶信息、授權列表等都保存在服務端的session中。如果把session中的認證信息都保存在JWT中,在服務端就沒有session存在的必要了。當服務端水平擴展的時候,就不用處理session復制(session replication)/ session黏連(sticky session)或是引入外部session存儲了。
從這個角度來說,這個優點確實存在,但實際上外部session存儲方案已經非常成熟了(比如Redis),在一些Framework的幫助下(比如spring-session和hazelcast),session復制也并沒有想象中的麻煩。所以除非你的應用訪問量非常非常非常(此處省略N個非常)大,使用cookie-session配合外部session存儲完全夠用了。
跨站請求偽造Cross-site request forgery(簡稱CSRF, 讀作 [sea-surf])是一種典型的利用cookie-session漏洞的攻擊,這里借用spring-security的一個例子來解釋CSRF:
假設你經常使用http://bank.example.com進行網上轉賬,在你提交轉賬請求時http://bank.example.com的前端代碼會提交一個HTTP請求:
POST /transfer HTTP/1.1 Host: bank.example.com cookie: JsessionID=randomid; Domain=bank.example.com; Secure; HttpOnly Content-Type: application/x-www-form-urlencoded amount=100.00&routingNumber=1234&account=9876
你圖方便沒有登出http://bank.example.com,隨后又訪問了一個惡意網站,該網站的HTML頁面包含了這樣一個表單:
<form action="https://bank.example.com/transfer" method="post"> <input type="hidden" name="amount" value="100.00"/> <input type="hidden" name="routingNumber" value="evilsRoutingNumber"/> <input type="hidden" name="account" value="evilsAccountNumber"/> <input type="submit" value="點擊就送!"/> </form>
你被“點擊就送”吸引了,當你點了提交按鈕時你已經向攻擊者的賬號轉了100元。現實中的攻擊可能更隱蔽,惡意網站的頁面可能使用Javascript自動完成提交。盡管惡意網站沒有辦法盜取你的session cookie(從而假冒你的身份),但惡意網站向http://bank.example.com發起請求時,你的cookie會被自動發送過去。
因此,有些人認為前端代碼將JWT通過HTTP header發送給服務端(而不是通過cookie自動發送)可以有效防護CSRF。在這種方案中,服務端代碼在完成認證后,會在HTTP response的header中返回JWT,前端代碼將該JWT存放到Local Storage里待用,或是服務端直接在cookie中保存HttpOnly=false的JWT。
在向服務端發起請求時,用Javascript取出JWT(否則前端Javascript代碼無權從cookie中獲取數據),再通過header發送回服務端通過認證。由于惡意網站的代碼無法獲取http://bank.example.com的cookie/Local Storage中的JWT,這種方式確實能防護CSRF,但將JWT保存在cookie/Local Storage中可能會給另一種攻擊可乘之機,我們一會詳細討論它:跨站腳本攻擊——XSS。
由于JWT要求有一個秘鑰,還有一個算法,生成的令牌看上去不可讀,不少人誤認為該令牌是被加密的。但實際上秘鑰和算法是用來生成簽名的,令牌本身不可讀僅是因為base64url
編碼,可以直接解碼,所以如果JWT中如果保存了敏感的信息,相對cookie-session將數據放在服務端來說,更不安全。
除了以上這些誤解外,使用JWT管理session還有如下缺點:
更多的空間占用。如果將原存在服務端session中的各類信息都放在JWT中保存在客戶端,可能造成JWT占用的空間變大,需要考慮cookie的空間限制等因素,如果放在Local Storage,則可能受到XSS攻擊。
更不安全。這里是特指將JWT保存在Local Storage中,然后使用Javascript取出后作為HTTP header發送給服務端的方案。在Local Storage中保存敏感信息并不安全,容易受到跨站腳本攻擊,跨站腳本(Cross site script,簡稱xss)是一種“HTML注入”,由于攻擊的腳本多數時候是跨域的,所以稱之為“跨域腳本”,這些腳本代碼可以盜取cookie或是Local Storage中的數據。
無法作廢已頒布的令牌。所有的認證信息都在JWT中,由于在服務端沒有狀態,即使你知道了某個JWT被盜取了,你也沒有辦法將其作廢。在JWT過期之前(你絕對應該設置過期時間),你無能為力。
不易應對數據過期。與上一條類似,JWT有點類似緩存,由于無法作廢已頒布的令牌,在其過期前,你只能忍受“過期”的數據。
看到這里后,你可能發現,將JWT保存在Local Storage中,并使用JWT來管理session并不是一個好主意,那有沒有可能“正確”地使用JWT來管理session呢?比如:
不再使用Local Storage存儲JWT,使用cookie,并且設置HttpOnly=true,這意味著只能由服務端保存以及通過自動回傳的cookie取得JWT,以便防御XSS攻擊
在JWT的內容中加入一個隨機值作為CSRF令牌,由服務端將該CSRF令牌也保存在cookie中,但設置HttpOnly=false,這樣前端Javascript代碼就可以取得該CSRF令牌,并在請求API時作為HTTP header傳回。服務端在認證時,從JWT中取出CSRF令牌與header中獲得CSRF令牌比較,從而實現對CSRF攻擊的防護
考慮到cookie的空間限制(大約4k左右),在JWT中盡可能只放“夠用”的認證信息,其他信息放在數據庫,需要時再獲取,同時也解決之前提到的數據過期問題
這個方案看上去是挺不錯的,恭喜你,你重新發明了cookie-session,可能實現還不一定有現有的好。
解釋:
JWT(其實還有SAML)最適合的應用場景就是“開票”,或者“簽字”。
在有紙化辦公時代,多部門、多組織之間的協同工作往往會需要拿著A部門領導的“簽字”或者“蓋章”去B部門“使用”或者“訪問”對應的資源,其實這種“領導簽字/蓋章”就是JWT,都是一種由具有一定權力的實體“簽發”并“授權”的“票據”。一般的,這種票據具有可驗證性(領導簽名/蓋章可以被驗證,且難于模仿),不可篡改性(涂改過的文件不被接受,除非在涂改處再次簽字確認);并且這種票據一般都是“一次性”使用的,在訪問到對應的資源后,該票據一般會被資源持有方收回留底,用于后續的審計、追溯等用途。
舉兩個例子:
員工李雷需要請假一天,于是填寫請假申請單,李雷在獲得其主管部門領導簽字后,將請假單交給HR部門韓梅梅,韓梅梅確認領導簽字無誤后,將請假單收回,并在公司考勤表中做相應記錄。
員工李雷和韓梅梅因工外出需要使用公司汽車一天,于是填寫用車申請單,簽字后李雷將申請單交給車隊司機老王,乘坐老王駕駛的車輛外出辦事,同時老王將用車申請單收回并存檔。
在以上的兩個例子中,“請假申請單”和“用車申請單”就是JWT中的payload,領導簽字就是base64后的數字簽名,領導是issuer,“HR部門的韓梅梅”和“司機老王”即為JWT的audience,audience需要驗證領導簽名是否合法,驗證合法后根據payload中請求的資源給予相應的權限,同時將JWT收回。
放到系統集成的場景中,JWT更適合一次性操作的認證:
服務B你好, 服務A告訴我,我可以操作<JWT內容>, 這是我的憑證(即JWT)
在這里,服務A負責認證用戶身份(相當于上例中領導批準請假),并頒布一個很短過期時間的JWT給瀏覽器(相當于上例中的請假單),瀏覽器(相當于上例中的請假員工)在向服務B的請求中帶上該JWT,則服務B(相當于上例中的HR員工)可以通過驗證該JWT來判斷用戶是否有權執行該操作。這樣,服務B就成為一個安全的無狀態的服務了。
在Web應用中,別再把JWT當做session使用,絕大多數情況下,傳統的cookie-session機制工作得更好
JWT適合一次性的命令認證,頒發一個有效期極短的JWT,即使暴露了危險也很小,由于每次操作都會生成新的JWT,因此也沒必要保存JWT,真正實現無狀態。
感謝各位的閱讀,以上就是“什么是JWT”的內容了,經過本文的學習后,相信大家對什么是JWT這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。