站長阿川

站長阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

站長精心設計,帶你實作 63 個小專案,得到作品集!

立即開始免費試讀!

開篇:一個經典的面試題

“說說看,使用者登入後拿到的 Token,前端應該怎麼存?”

這個問題看似簡單,卻能清晰地分辨出一個前端開發者對安全的理解深度。是存到 localStoragesessionStorage?還是 Cookie?又或者是內存裡?不同的選擇背後,是截然不同的安全考量。

今天,來聊一聊 Token 的存儲之道,讓你不僅知道怎麼做,更明白為什麼這麼做。

Token存儲示意圖

選項一:Web Storage(localStorage / sessionStorage

這是最直觀、最容易想到的方案。

// 登入成功後
const token = 'your_jwt_token_here';
localStorage.setItem('auth_token', token);

// 後續請求時帶上
axios.interceptors.request.use((config) => {
  const token = localStorage.getItem('auth_token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

優點:

  • 簡單易用:API 簡單,上手快。
  • 永久存儲localStorage):除非手動清除,否則一直存在。
  • 會話期存儲sessionStorage):頁面關閉即清除,更安全一點。

致命缺點:

  • 極易受到 XSS (跨站腳本攻擊) 的攻擊。這是最核心的問題。如果網站存在 XSS 漏洞,攻擊者的惡意腳本可以輕易地讀取到 localStorage 中的所有 Token,從而竊取使用者身份。

結論: 不推薦,尤其對於敏感應用。 除非你的應用完全不存在 XSS 風險(但這幾乎不可能),或者 Token 的安全級別要求不高。

選項二:Cookie

Cookie 是傳統且常見的身份驗證載體。

// 服務端設置 Cookie (HTTP Response Header)
Set-Cookie: auth_token=your_jwt_token_here; Path=/; HttpOnly; Secure

// 前端無需特殊處理,瀏覽器會自動在每次請求中攜帶

注意這裡的兩個關鍵屬性:

  • HttpOnly這是對抗 XSS 的神器。設置了 HttpOnly 的 Cookie 無法通過 JavaScript 的 document.cookie API 訪問,這意味著即使發生 XSS,攻擊者也無法竊取到 Token。
  • Secure:強制 Cookie 只能在 HTTPS 協議下被發送,防止在網路傳輸中被竊聽。

優點:

  • 免疫 XSS(得益於 HttpOnly):無法通過 JS 讀取,安全性高。
  • 可控制生命周期:通過 ExpiresMax-Age 設置過期時間。
  • 自動管理:瀏覽器自動在同源請求中攜帶。

缺點:

  • 容易受到 CSRF (跨站請求偽造) 的攻擊。因為瀏覽器會自動在請求中帶上 Cookie,攻擊者可以誘導使用者點擊一個鏈接,從而以使用者的身份發起惡意請求。
  • 需要額外的 CSRF 防護措施,如使用 Anti-CSRF Token、驗證 Origin/Referer Header 等。

結論: 是個可行的方案,但必須配套完善的 CSRF 防禦機制。

選項三:內存(Memory)

將 Token 保存在 JavaScript 變數中。

let inMemoryToken = null;

// 登入成功後
const login = async () => {
  const response = await loginAPI(username, password);
  inMemoryToken = response.data.token; // 存到內存變數
};

// 請求攔截器中添加
axios.interceptors.request.use((config) => {
  if (inMemoryToken) {
    config.headers.Authorization = `Bearer ${inMemoryToken}`;
  }
  return config;
});

// 退出登入或頁面刷新時,Token 消失

優點:

  • 安全性極高:由於 Token 只存在於當前頁面的內存中,關閉頁面或刷新頁面後 Token 立即消失。XSS 攻擊者很難通過一次性注入的腳本持續地竊取到 Token(除非攻擊代碼常駐內存)。

缺點:

  • 體驗差:頁面一旦刷新,Token 就沒了,使用者需要重新登入。這對於單頁應用 (SPA) 來說是致命的。

結論: 適用於安全要求極高、不介意頻繁登入的場景(如銀行系統)。 對於普通 Web 應用,體驗不可接受。


終極方案:組合拳 + 架構思維

既然沒有完美的銀彈,現代前端的最佳實踐通常是 組合方案架構優化

實踐一:Cookie(HttpOnly + Secure) + 防禦 CSRF

這是最傳統但依然非常穩健的方案。

  1. 後端在登入成功後,設置一個 HttpOnlySecure 的 Cookie 來存放 Token(可以是 JWT,也可以是 Session ID)。
  2. 前端基本不用操心 Token 的存儲和攜帶問題,由瀏覽器自動完成。
  3. 後端必須部署完善的 CSRF 防護策略,例如:
    • 從 Cookie 中讀取 Token 或 Session ID 進行身份驗證。
    • 同時,要求請求必須攜帶一個額外的(由後端生成並通過 API 返回給前端的)X-CSRF-Token Header,並與 Session 中存儲的值進行比對。

實踐二:Access Token + Refresh Token

這是目前 API 接口認證非常流行的方案,完美解決了內存存儲體驗差的問題。

  1. 登入:使用者輸入密碼登入。
  2. 返回雙 Token:服務端返回兩個 Token:
    • access_token:短期有效(例如 2 小時),用於請求受保護的 API。
    • refresh_token:長期有效(例如 7 天),僅用於獲取新的 access_token,不應具備API訪問權限。
  3. 存儲策略
    • access_token存入內存。這樣即使被 XSS 窃取,有效期也很短,風險可控。
    • refresh_token存入 HttpOnly Cookie。因為它有效期長,必須嚴加保護。由於其本身不直接用於業務請求,即使遭遇 CSRF,攻擊者也無法用它來做任何關鍵操作(只能用來換一個短期的 access_token,而該 access_token 又會因為存在於內存而難以被攻擊者獲取)。
  4. 無感刷新:當 access_token 過期後,前端自動(通過 refresh_token)調用刷新接口獲取新的 access_token,使用者無感知。

這個方案在安全性和使用者體驗之間取得了絕佳的平衡,是當前眾多大型應用的首選。


總結與建議

存儲位置 優點 缺點 適用場景
Web Storage 簡單易用 極易被 XSS 不推薦用於存敏感 Token
Cookie 可防 XSS (HttpOnly) 需防禦 CSRF 傳統 Web 應用(需配 CSRF 防禦)
內存 安全性極高 頁面刷新即失效 安全至上、不介意體驗的場景
組合策略 安全與體驗的平衡 架構稍複雜 現代 Web 應用最佳實踐

給你的最終建議:

  • 如果你在做的是一個簡單的、內部使用的、對安全性要求不高的工具,用 localStorage 圖個方便也無可厚非,但要清楚風險。
  • 如果你在做的是一個傳統的、服務端渲染的多頁應用,使用 HttpOnly Cookie 並配套 CSRF 防護是標準做法。
  • 如果你在做的是一個現代化的 SPA(如 React/Vue 應用),強烈推薦研究並採用 Access Token (內存) + Refresh Token (HttpOnly Cookie) 的方案。

安全沒有絕對,只有相對的權衡。理解每種方案的利弊,並根據你的實際業務場景做出最適合的選擇,才是最重要的。

下次再見!🌈

再見


原文出處:https://juejin.cn/post/7545017768518533135

按讚的人:

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
站長阿川

站長阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

站長精心設計,帶你實作 63 個小專案,得到作品集!

立即開始免費試讀!