當(dāng)前位置:首頁 > 公眾號精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]經(jīng)過前面兩篇文章《JSON Web Token - 在Web應(yīng)用間安全地傳遞信息》《八幅漫畫理解使用JSON Web Token設(shè)計單點登錄系統(tǒng)》的科普,相信大家應(yīng)該已經(jīng)知道了 JWT 協(xié)議是什么了。

經(jīng)過前面兩篇文章《JSON Web Token - 在Web應(yīng)用間安全地傳遞信息》《八幅漫畫理解使用JSON Web Token設(shè)計單點登錄系統(tǒng)》的科普,相信大家應(yīng)該已經(jīng)知道了 JWT 協(xié)議是什么了。至少看到

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJxaWFubWlJZCI6InFtMTAzNTNzaEQiLCJpc3MiOiJhcHBfcW0xMDM1M3NoRCIsInBsYXRmb3JtIjoiYXBwIn0.cMNwyDTFVYMLL4e7ts50GFHTvlSJLDpePtHXzu7z9j4 

這樣形如 A.B.C 的字符串時能敏感地認(rèn)出這是使用了 jwt。發(fā)了這兩篇文章后,有不少讀者在文末留言,表達(dá)了對 jwt 使用方式的一些疑惑,以及到底哪些場景適合使用 jwt。我并不是 jwt 方面的專家,和不少讀者一樣,起初研究時我也存在相同疑惑,甚至在逐漸接觸后產(chǎn)生了更大的疑惑,經(jīng)過這段時間項目中的使用和一些自己思考,把個人的總結(jié)整理成此文。

編碼,簽名,加密

這些基礎(chǔ)知識簡單地介紹下,千萬別搞混了三個概念。在 jwt 中恰好同時涉及了這三個概念,筆者用大白話來做下通俗的講解(非嚴(yán)謹(jǐn)定義,供個人理解)

編碼(encode)和解碼(decode)

一般是編碼解碼是為了方便以字節(jié)的方式表示數(shù)據(jù),便于存儲和網(wǎng)絡(luò)傳輸。整個 jwt 串會被置于 http 的 Header 或者 url 中,為了不出現(xiàn)亂碼解析錯誤等意外,編碼是有必要的。在 jwt 中以.分割的三個部分都經(jīng)過 base64 編碼(secret 部分是否進(jìn)行 base64 編碼是可選的,header 和 payload 則是必須進(jìn)行 base64 編碼)。注意,編碼的一個特點:編碼和解碼的整個過程是可逆的。得知編碼方式后,整個 jwt 串便是明文了,隨意找個網(wǎng)站驗證下解碼后的內(nèi)容:

深入理解JWT的使用場景和優(yōu)劣 base64

所以注意一點,payload 是一定不能夠攜帶敏感數(shù)據(jù)如密碼等信息的。

簽名(signature)

簽名的目的主要是為了驗證我是“我”。jwt 中常用的簽名算法是 HS256,可能大多數(shù)人對這個簽名算法不熟悉,但 md5,sha 這樣的簽名算法肯定是為人熟知的,簽名算法共同的特點是整個過程是不可逆的。由于簽名之前的主體內(nèi)容(header,payload)會攜帶在 jwt 字符串中,所以需要使用帶有密鑰(yuè)的簽名算法,密鑰是服務(wù)器和簽發(fā)者共享的。header 部分和 payload 部分如果被篡改,由于篡改者不知道密鑰是什么,也無法生成新的 signature 部分,服務(wù)端也就無法通過,在 jwt 中,消息體是透明的,使用簽名可以保證消息不被篡改。

前面轉(zhuǎn)載的文章中,原作者將 HS256 稱之為加密算法,不太嚴(yán)謹(jǐn)。

加密(encryption)

加密是將明文信息改變?yōu)殡y以讀取的密文內(nèi)容,使之不可讀。只有擁有解密方法的對象,經(jīng)由解密過程,才能將密文還原為正??勺x的內(nèi)容。加密算法通常按照加密方式的不同分為對稱加密(如 AES)和非對稱加密(如 RSA)。你可能會疑惑:“jwt 中哪兒涉及加密算法了?”,其實 jwt 的 第一部分(header) 中的 alg 參數(shù)便可以指定不同的算法來生成第三部分(signature),大部分支持 jwt 的框架至少都內(nèi)置 rsa 這種非對稱加密方式。這里誕生了第一個疑問

疑問:一提到 rsa,大多數(shù)人第一想到的是非對稱加密算法,而 jwt 的第三部分明確的英文定義是 signature,這不是矛盾嗎?

劃重點!

rsa 加密rsa 簽名 是兩個概念!(嚇得我都換行了)

這兩個用法很好理解:

  • 既然是加密,自然是不希望別人知道我的消息,只有我自己才能解密,所以公鑰負(fù)責(zé)加密,私鑰負(fù)責(zé)解密。這是大多數(shù)的使用場景,使用 rsa 來加密。

  • 既然是簽名,自然是希望別人不能冒充我發(fā)消息,只有我才能發(fā)布簽名,所以私鑰負(fù)責(zé)簽名,公鑰負(fù)責(zé)驗證。

所以,在客戶端使用 rsa 算法生成 jwt 串時,是使用私鑰來“加密”的,而公鑰是公開的,誰都可以解密,內(nèi)容也無法變更(篡改者無法得知私鑰)。

所以,在 jwt 中并沒有純粹的加密過程,而是使加密之虛,行簽名之實。

什么場景該適合使用jwt?

來聊聊幾個場景,注意,以下的幾個場景不是都和jwt貼合。

  1. 一次性驗證

比如用戶注冊后需要發(fā)一封郵件讓其激活賬戶,通常郵件中需要有一個鏈接,這個鏈接需要具備以下的特性:能夠標(biāo)識用戶,該鏈接具有時效性(通常只允許幾小時之內(nèi)激活),不能被篡改以激活其他可能的賬戶…這種場景就和 jwt 的特性非常貼近,jwt 的 payload 中固定的參數(shù):iss 簽發(fā)者和 exp 過期時間正是為其做準(zhǔn)備的。

  1. restful api 的無狀態(tài)認(rèn)證

使用 jwt 來做 restful api 的身份認(rèn)證也是值得推崇的一種使用方案。客戶端和服務(wù)端共享 secret;過期時間由服務(wù)端校驗,客戶端定時刷新;簽名信息不可被修改…spring security oauth jwt 提供了一套完整的 jwt 認(rèn)證體系,以筆者的經(jīng)驗來看:使用 oauth2 或 jwt 來做 restful api 的認(rèn)證都沒有大問題,oauth2 功能更多,支持的場景更豐富,后者實現(xiàn)簡單。

  1. 使用 jwt 做單點登錄+會話管理(不推薦)

在《八幅漫畫理解使用JSON Web Token設(shè)計單點登錄系統(tǒng)》一文中提及了使用 jwt 來完成單點登錄,本文接下來的內(nèi)容主要就是圍繞這一點來進(jìn)行討論。如果你正在考慮使用 jwt+cookie 代替 session+cookie ,我強(qiáng)力不推薦你這么做。

首先明確一點:使用 jwt 來設(shè)計單點登錄系統(tǒng)是一個不太嚴(yán)謹(jǐn)?shù)恼f法。首先 cookie+jwt 的方案前提是非跨域的單點登錄(cookie 無法被自動攜帶至其他域名),其次單點登錄系統(tǒng)包含了很多技術(shù)細(xì)節(jié),至少包含了身份認(rèn)證和會話管理,這還不涉及到權(quán)限管理。如果覺得比較抽象,不妨用傳統(tǒng)的 session+cookie 單點登錄方案來做類比,通常我們可以選擇 spring security(身份認(rèn)證和權(quán)限管理的安全框架)和 spring session(session 共享)來構(gòu)建,而選擇用 jwt 設(shè)計單點登錄系統(tǒng)需要解決很多傳統(tǒng)方案中同樣存在和本不存在的問題,以下一一詳細(xì)羅列。

jwt token泄露了怎么辦?

前面的文章下有不少人留言提到這個問題,我則認(rèn)為這不是問題。傳統(tǒng)的 session+cookie 方案,如果泄露了 sessionId,別人同樣可以盜用你的身份。揚湯止沸不如釜底抽薪,不妨來追根溯源一下,什么場景會導(dǎo)致你的 jwt 泄露。

遵循如下的實踐可以盡可能保護(hù)你的 jwt 不被泄露:使用 https 加密你的應(yīng)用,返回 jwt 給客戶端時設(shè)置 httpOnly=true 并且使用 cookie 而不是 LocalStorage 存儲 jwt,這樣可以防止 XSS 攻擊和 CSRF 攻擊(對這兩種攻擊感興趣的童鞋可以看下 spring security 中對他們的介紹CSRF,XSS)

你要是正在使用 jwt 訪問一個接口,這個時候你的同事跑過來把你的 jwt 抄走了,這種泄露,恕在下無力

secret如何設(shè)計

jwt 唯一存儲在服務(wù)端的只有一個 secret,個人認(rèn)為這個 secret 應(yīng)該設(shè)計成和用戶相關(guān)的屬性,而不是一個所有用戶公用的統(tǒng)一值。這樣可以有效的避免一些注銷和修改密碼時遇到的窘境。

注銷和修改密碼

傳統(tǒng)的 session+cookie 方案用戶點擊注銷,服務(wù)端清空 session 即可,因為狀態(tài)保存在服務(wù)端。但 jwt 的方案就比較難辦了,因為 jwt 是無狀態(tài)的,服務(wù)端通過計算來校驗有效性。沒有存儲起來,所以即使客戶端刪除了 jwt,但是該 jwt 還是在有效期內(nèi),只不過處于一個游離狀態(tài)。分析下痛點:注銷變得復(fù)雜的原因在于 jwt 的無狀態(tài)。我提供幾個方案,視具體的業(yè)務(wù)來決定能不能接受。

  • 僅僅清空客戶端的 cookie,這樣用戶訪問時就不會攜帶 jwt,服務(wù)端就認(rèn)為用戶需要重新登錄。這是一個典型的假注銷,對于用戶表現(xiàn)出退出的行為,實際上這個時候攜帶對應(yīng)的 jwt 依舊可以訪問系統(tǒng)。

  • 清空或修改服務(wù)端的用戶對應(yīng)的 secret,這樣在用戶注銷后,jwt 本身不變,但是由于 secret 不存在或改變,則無法完成校驗。這也是為什么將 secret 設(shè)計成和用戶相關(guān)的原因。

  • 借助第三方存儲自己管理 jwt 的狀態(tài),可以以 jwt 為 key,實現(xiàn)去 redis 一類的緩存中間件中去校驗存在性。方案設(shè)計并不難,但是引入 redis 之后,就把無狀態(tài)的 jwt 硬生生變成了有狀態(tài)了,違背了 jwt 的初衷。實際上這個方案和 session 都差不多了。

修改密碼則略微有些不同,假設(shè)號被到了,修改密碼(是用戶密碼,不是 jwt 的 secret)之后,盜號者在原 jwt 有效期之內(nèi)依舊可以繼續(xù)訪問系統(tǒng),所以僅僅清空 cookie 自然是不夠的,這時,需要強(qiáng)制性的修改 secret。在我的實踐中就是這樣做的。

續(xù)簽問題

續(xù)簽問題可以說是我抵制使用 jwt 來代替?zhèn)鹘y(tǒng) session 的最大原因,因為 jwt 的設(shè)計中我就沒有發(fā)現(xiàn)它將續(xù)簽認(rèn)為是自身的一個特性。傳統(tǒng)的 cookie 續(xù)簽方案一般都是框架自帶的,session 有效期 30 分鐘,30 分鐘內(nèi)如果有訪問,session 有效期被刷新至 30 分鐘。而 jwt 本身的 payload 之中也有一個 exp 過期時間參數(shù),來代表一個 jwt 的時效性,而 jwt 想延期這個 exp 就有點身不由己了,因為 payload 是參與簽名的,一旦過期時間被修改,整個 jwt 串就變了,jwt 的特性天然不支持續(xù)簽!

如果你一定要使用 jwt 做會話管理(payload 中存儲會話信息),也不是沒有解決方案,但個人認(rèn)為都不是很令人滿意

  1. 每次請求刷新 jwt

jwt 修改 payload 中的 exp 后整個 jwt 串就會發(fā)生改變,那…就讓它變好了,每次請求都返回一個新的 jwt 給客戶端。太暴力了,不用我贅述這樣做是多么的不優(yōu)雅,以及帶來的性能問題。

但,至少這是最簡單的解決方案。

  1. 只要快要過期的時候刷新 jwt

一個上述方案的改造點是,只在最后的幾分鐘返回給客戶端一個新的 jwt。這樣做,觸發(fā)刷新 jwt 基本就要看運氣了,如果用戶恰巧在最后幾分鐘訪問了服務(wù)器,觸發(fā)了刷新,萬事大吉;如果用戶連續(xù)操作了 27 分鐘,只有最后的 3 分鐘沒有操作,導(dǎo)致未刷新 jwt,無疑會令用戶抓狂。

  1. 完善 refreshToken

借鑒 oauth2 的設(shè)計,返回給客戶端一個 refreshToken,允許客戶端主動刷新 jwt。一般而言,jwt 的過期時間可以設(shè)置為數(shù)小時,而 refreshToken 的過期時間設(shè)置為數(shù)天。

我認(rèn)為該方案并可行性是存在的,但是為了解決 jwt 的續(xù)簽把整個流程改變了,為什么不考慮下 oauth2 的 password 模式和 client 模式呢?

  1. 使用 redis 記錄獨立的過期時間

實際上我的項目中由于歷史遺留問題,就是使用 jwt 來做登錄和會話管理的,為了解決續(xù)簽問題,我們在 redis 中單獨會每個 jwt 設(shè)置了過期時間,每次訪問時刷新 jwt 的過期時間,若 jwt 不存在與 redis 中則認(rèn)為過期。

tips:精確控制 redis 的過期時間不是件容易的事,可以參考我最近的一篇借助于 spring session 講解 redis 過期時間的排坑記錄。

同樣改變了 jwt 的流程,不過嘛,世間安得兩全法。我只能奉勸各位還未使用 jwt 做會話管理的朋友,盡量還是選用傳統(tǒng)的 session+cookie 方案,有很多成熟的分布式 session 框架和安全框架供你開箱即用。

jwt,oauth2,session千絲萬縷的聯(lián)系

具體的對比不在此文介紹,就一位讀者的留言回復(fù)下它的提問

這么長一個字符串,還不如我把數(shù)據(jù)存到數(shù)據(jù)庫,給一個長的很難碰撞的key來映射,也就是專用token。

這位兄弟認(rèn)為 jwt 太長了,是不是可以考慮使用和 oauth2 一樣的 uuid 來映射。這里面自然是有問題的,jwt 不僅僅是作為身份的認(rèn)證(驗證簽名是否正確,簽發(fā)者是否存在,有限期是否過期),還在其 payload 中存儲著會話信息,這是 jwt 和 session 的最大區(qū)別,一個在客戶端攜帶會話信息,一個在服務(wù)端存儲會話信息。如果真的是要將 jwt 的信息置于在共享存儲中,那再找不到任何使用 jwt 的意義了。

jwt 和 oauth2 都可以用于 restful 的認(rèn)證,就我個人的使用經(jīng)驗來看,spring security oauth2 可以很好的使用多種認(rèn)證模式:client 模式,password 模式,implicit 模式(authorization code 模式不算單純的接口認(rèn)證模式),也可以很方便的實現(xiàn)權(quán)限控制,什么樣的 api 需要什么樣的權(quán)限,什么樣的資源需要什么樣的 scope…而 jwt 我只用它來實現(xiàn)過身份認(rèn)證,功能較為單一(可能是我沒發(fā)現(xiàn)更多用法)。

總結(jié)

在 web 應(yīng)用中,使用 jwt 代替 session 存在不小的風(fēng)險,你至少得解決本文中提及的那些問題,絕大多數(shù)情況下,傳統(tǒng)的 cookie-session 機(jī)制工作得更好。jwt 適合做簡單的 restful api 認(rèn)證,頒發(fā)一個固定有效期的 jwt,降低 jwt 暴露的風(fēng)險,不要對 jwt 做服務(wù)端的狀態(tài)管理,這樣才能體現(xiàn)出 jwt 無狀態(tài)的優(yōu)勢。

可能對 jwt 的使用場景還有一些地方未被我察覺,后續(xù)會研究下 spring security oauth jwt 的源碼,不知到時會不會有新發(fā)現(xiàn)。



免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉