關於jwt的思考

關於jwt的思考

jwt是個做用戶權限認證的方案,科普的內容參考相關文檔吧,這裏提出幾個關於jwt的思考:

現有項目架構:

pc項目->pc服務器->api服務器
app項目->api服務器

1. jwt是否需要服務器存儲用戶狀態

按照jwt的思路,服務端是不需要存儲用戶狀態的,只要有祕鑰+過期時間就可以實現用戶的認證和過期,至於讀庫vs加解密驗證哪個過程對服務器的壓力更大,這個可能需要對比測試,但從原理和常識來講,存庫讀庫的成本應該更高一點。無庫產生的加解密開銷相對於讀寫庫應該是非常小的,而且無庫可以輕鬆做到跨服務器的認證。

2. jwt方案中token的安全問題

分爲兩個安全問題:

  • token泄露,泄露一般存在兩個地方,1是傳輸層,2是客戶端。先考慮傳輸層:http被竊聽,或者https被破解(https的安全性這裏不做討論),那麼如果token在傳輸層被攔截,傳統的cookie存儲的sessionId也有一樣的問題。再說客戶端,一樣的情況,如果cookie可以被竊取,token也沒辦法解決這個問題。已經做過的測試是:攔截到cookie後,把cookie放在另一臺電腦上也是可以使用的,這個跟token是一樣的。

  • 還有一種情況是重放攻擊,http請求被攔截重放,這個安全性對於cookie和jwt是一樣的,避免這個問題需要配合其他手段,但基本很難避免。

綜上,jwt碰到的安全問題跟傳統方式一樣。

3. jwt如何解決續簽問題

傳統的cookie的續簽方案一般都是框架自帶的,session有效期30分鐘,30分鐘內如果有訪問,session有效期被延長30分鐘。那麼jwt是怎麼實現的呢,細節沒看完,不過基本的邏輯是頻繁重簽名(不知道爲什麼有人這麼幹,開銷應該不小,而且問題挺多),或者是有效期30分鐘,服務器發現token要過期了,提前三分鐘重籤並返回新的token,客戶端每次請求都檢測新舊token,如果不一致更新本地token(這個可以放在http的請求預處理裏,複雜度和開銷都不大)。關於新token的發放導致舊token有效期內的訪問失效的問題參見這裏的token新舊更替問題討論 。這種方案就可以實現瀏覽器裏傳統cookie的續簽需求,以及app7天內登陸就可以持續刷新登陸狀態的問題(app比較特殊,每天第一次訪問時刷新一下token)。

4. jwt如何解決註銷問題

好了,jwt最大的問題來了,怎麼註銷?先看傳統的session是怎麼註銷的:用戶點擊退出,調用後臺退出接口,也就是session註銷接口,依託於後臺的狀態更新。那麼服務端做的呢,如果是用文件或者數據庫存儲的,那麼通過刪記錄是可以後臺強制踢出的,放在內存裏就不要想了(如果用戶量大了放內存的話服務器也吃不消,放文件裏io太頻繁基本也不靠譜,還好有了Redis)。jwt最大的問題就在於後臺沒有存儲用戶狀態,用戶退出的話只是客戶端刪掉了token,然而此token在有效期內還是有效的,也就是說如果token泄露的話就麻煩了,不過token泄露的問題已經在上面講過了,和cookie是同一個問題。那麼最麻煩的就是怎麼讓一個token在用戶註銷後失效,以及後臺強制退出,這個jwt是沒辦法的,因爲jwt的無狀態和用戶狀態維護是個矛盾衝突的話題。如果要解決就要建立一個黑名單,也就是把用戶註銷後的token放到redis裏,然後每次校驗黑名單(這裏還是用到了數據庫),

5. 使用jwt+Redis黑名單的方案

接上個問題,jwt推崇的無狀態和跨服務器認證在數據庫的出現後,貌似沒有任何優勢,真的沒有優勢嗎?也不全是,至少有兩個小優勢,第一,存儲黑名單(也就是註銷後的用戶或者黑戶)比起存儲登錄之後的用戶這個量級都是相當小的,存儲量下降&讀取速度提高。第二個優勢是app和pc能共用同一套認證機制,也就意味着前後端徹底的分離,不必再爲cookie和session認證單獨搭一個服務器。

6. 用了jwt之後html服務怎麼提供呢

對於前後端分離的項目來說,pc服務器的兩個任務1是做認證(jwt已經解決),2是提供html服務。html服務可以交給nginx或者放到cdn,無論哪個方案都比tomcat之類的靜態資源處理能力更強大,也就是說html和js等靜態資源全部交給靜態資源服務器來處理。那麼安全問題又來了,怎麼對文件做權限控制呢?對於一個前後端分離的項目來說,html一般不會嵌套後端的代碼,所以html沒有所謂的安全問題,換句話說html里根本沒有任何有價值的內容。對於js來說,裏面包含了業務邏輯,實際上對js做限制也是沒有任何意義的,因爲前端的代碼是暴露給客戶端的,即便控制,黑客登錄之後也是能看到你的代碼的,惟一能做的就是壓縮混淆,把壓縮後的代碼放到線上,源碼不放到線上,最大程度增加通過閱讀js讀取業務邏輯的難度(實際意義也不大,尤其對於有些公司壓根連壓縮這一步都不做的,更沒有這個問題的顧慮了)。那麼也就是說前後端分離的項目裏html(沒有後端代碼嵌入)和js是沒有安全的考慮必要的,真正要考慮的大概也就是圖片的防盜鏈和pdf等靜態資源的處理吧,這個因爲對於後端不是很熟悉所以不做深入討論,對於pdf等資源能想到的也就是通過需要授權的接口去拿pdf的路徑吧。

7. 到底要不要數據庫

如果不考慮用戶註銷後一定要token失效和強制退出需求的話,是不需要數據庫的,即便加上redis對於傳統方案來說也是有上文提到的兩個優勢。而且其實註銷後一定要token失效主要也是考慮token泄露的問題(見上文),所以如果有踢出用戶登錄需求的話,還是要有數據庫做黑名單存儲的,一旦用戶被拉入黑名單,就要立馬停掉用戶的簽名發放,所以這個問題並不單單是認證的問題,還有簽名發放的問題。

8. 用戶認證的終極解決方案(跨服務器)

前提就是跨服務,實際上jwt本身已經實現了跨服務(無狀態),既然服務端不存儲用戶狀態,只要多個服務器之間使用共同的祕鑰和加密方案就可以實現x.abc.com裏登錄之後在y.abc.com那臺服務器做登錄認證。但是問題上面也說了,如果不考慮註銷和強制退出的情況的話,這個話題也就到處爲止了。但是如果完美主義呢?當然還是要實現這兩個功能,也就是要有黑名單服務器,或者說認證服務器auth.abc.com,無論x.abc.com還是y.abc.com裏登錄或者註銷都要先通過auth.abc.com,但是帶來的讀寫不一致和額外的認證開銷問題大概也是一個歷史性難題吧。或許也可以參考Oauth2.0的方案,做隱式認證。不存儲用戶的狀態的話,jwt跨服務器應該是個比較簡單的解決方案吧,但如果一個公司有跨服務器需求的話,那麼規模之大,裏面的後端童鞋應該有更爲專業的方案吧,歡迎分享。此段不專業莫要踩我。


結論:

上文闡述了作爲一個卑微的前端能想到的jwt的問題和思考,總結來說,使用jwt可以實現真正的前後端分離,瀏覽器可以和app用一樣的認證機制,無論對服務器的搭建還是服務器開銷都是不錯的優化,至於黑名單的設置,這個看需求吧。


彩蛋

爲什麼會有彩蛋呢,因爲結論裏不能說太多廢話,就擱這裏說了,jwt主要解決了瀏覽器和app共用一個服務器的問題,也就是少了一個pc服務器。
有看客就要問了,那你怎麼看node呢,ssr?pwa?字節碼?
這個當然要且看下回分曉了️️��

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章