“說說看,使用者登入後拿到的 Token,前端應該怎麼存?”
這個問題看似簡單,卻能清晰地分辨出一個前端開發者對安全的理解深度。是存到 localStorage
?sessionStorage
?還是 Cookie
?又或者是內存裡?不同的選擇背後,是截然不同的安全考量。
今天,來聊一聊 Token 的存儲之道,讓你不僅知道怎麼做,更明白為什麼這麼做。
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;
});
優點:
localStorage
):除非手動清除,否則一直存在。sessionStorage
):頁面關閉即清除,更安全一點。致命缺點:
localStorage
中的所有 Token,從而竊取使用者身份。結論: 不推薦,尤其對於敏感應用。 除非你的應用完全不存在 XSS 風險(但這幾乎不可能),或者 Token 的安全級別要求不高。
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 協議下被發送,防止在網路傳輸中被竊聽。優點:
HttpOnly
):無法通過 JS 讀取,安全性高。Expires
或 Max-Age
設置過期時間。缺點:
結論: 是個可行的方案,但必須配套完善的 CSRF 防禦機制。
將 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 消失
優點:
缺點:
結論: 適用於安全要求極高、不介意頻繁登入的場景(如銀行系統)。 對於普通 Web 應用,體驗不可接受。
既然沒有完美的銀彈,現代前端的最佳實踐通常是 組合方案 和 架構優化。
這是最傳統但依然非常穩健的方案。
HttpOnly
、Secure
的 Cookie 來存放 Token(可以是 JWT,也可以是 Session ID)。X-CSRF-Token
Header,並與 Session 中存儲的值進行比對。這是目前 API 接口認證非常流行的方案,完美解決了內存存儲體驗差的問題。
access_token
:短期有效(例如 2 小時),用於請求受保護的 API。refresh_token
:長期有效(例如 7 天),僅用於獲取新的 access_token
,不應具備API訪問權限。access_token
:存入內存。這樣即使被 XSS 窃取,有效期也很短,風險可控。refresh_token
:存入 HttpOnly
Cookie。因為它有效期長,必須嚴加保護。由於其本身不直接用於業務請求,即使遭遇 CSRF,攻擊者也無法用它來做任何關鍵操作(只能用來換一個短期的 access_token
,而該 access_token
又會因為存在於內存而難以被攻擊者獲取)。access_token
過期後,前端自動(通過 refresh_token
)調用刷新接口獲取新的 access_token
,使用者無感知。這個方案在安全性和使用者體驗之間取得了絕佳的平衡,是當前眾多大型應用的首選。
存儲位置 | 優點 | 缺點 | 適用場景 |
---|---|---|---|
Web Storage | 簡單易用 | 極易被 XSS | 不推薦用於存敏感 Token |
Cookie | 可防 XSS (HttpOnly ) |
需防禦 CSRF | 傳統 Web 應用(需配 CSRF 防禦) |
內存 | 安全性極高 | 頁面刷新即失效 | 安全至上、不介意體驗的場景 |
組合策略 | 安全與體驗的平衡 | 架構稍複雜 | 現代 Web 應用最佳實踐 |
給你的最終建議:
localStorage
圖個方便也無可厚非,但要清楚風險。HttpOnly
Cookie 並配套 CSRF 防護是標準做法。HttpOnly
Cookie) 的方案。安全沒有絕對,只有相對的權衡。理解每種方案的利弊,並根據你的實際業務場景做出最適合的選擇,才是最重要的。