
概念概覽
flowchart TD Data["前後端資料儲存機制"] --> Client["客戶端儲存"] Data --> Server["伺服器端儲存"] Data --> Token["Token 機制"] Client --> Cookie["Cookie<br/>~4KB / 自動傳送"] Client --> LS["LocalStorage<br/>~5MB / 永久"] Client --> SS["SessionStorage<br/>~5MB / 分頁關閉清除"] Server --> Session["Session<br/>儲存在伺服器<br/>透過 Cookie 識別"] Token --> JWT["JWT Token<br/>自包含憑證<br/>無狀態"] style Data fill:#f96,stroke:#333,stroke-width:2px style Client fill:#bfb,stroke:#333 style Server fill:#bbf,stroke:#333 style Token fill:#fbf,stroke:#333
資料儲存方式比較
| 特性 | Cookie | LocalStorage | SessionStorage | Session | Token |
|---|---|---|---|---|---|
| 儲存位置 | 瀏覽器 | 瀏覽器 | 瀏覽器 | 伺服器 | 瀏覽器 |
| 容量限制 | ~4KB | ~5MB | ~5MB | 無限制 | ~8KB |
| 生命週期 | 可設定 | 永久 | 分頁關閉 | 可設定 | 可設定 |
| 自動傳送 | ✅ | ❌ | ❌ | ✅(via Cookie) | ❌ |
| 跨域存取 | 同源 | 同源 | 同源 | 伺服器控制 | 無限制 |
Cookie
基本概念
Cookie 是伺服器發送給瀏覽器的小型資料,瀏覽器會儲存並在後續請求中自動帶回。
首次請求
瀏覽器 伺服器
│ ─── GET /login ────────────→ │
│ ←── Set-Cookie: session=abc ── │
後續請求(自動帶上 Cookie)
│ ─── GET /profile ──────────→ │
│ Cookie: session=abc │
Cookie 屬性
// 伺服器設定 Cookie
Set-Cookie: token=abc123;
Path=/;
Domain=.example.com;
Expires=Thu, 01 Jan 2025 00:00:00 GMT;
HttpOnly;
Secure;
SameSite=Strict
// JavaScript 設定 Cookie(無法設定 HttpOnly)
document.cookie = "theme=dark; path=/; max-age=86400";| 屬性 | 說明 |
|---|---|
| HttpOnly | JavaScript 無法存取,防止 XSS |
| Secure | 只在 HTTPS 傳送 |
| SameSite | 防止 CSRF(Strict/Lax/None) |
| Path | Cookie 生效路徑 |
| Domain | Cookie 生效網域 |
| Max-Age/Expires | 過期時間 |
Session
基本概念
Session 是存在伺服器端的使用者狀態,透過 Session ID(通常存在 Cookie)識別使用者。
┌─────────────────────────────────────────────────────────┐
│ 伺服器 │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Session Storage │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ "abc123" → { userId: 1, name: "John" } │ │ │
│ │ │ "def456" → { userId: 2, name: "Jane" } │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
↑
│ Session ID = "abc123"
│
瀏覽器 Cookie
Session vs Cookie
// Cookie-based: 狀態存在客戶端
Set-Cookie: user={"id":1,"name":"John"} // ❌ 不安全
// Session-based: 狀態存在伺服器
Set-Cookie: sessionId=abc123 // ✅ 只傳 IDToken (JWT)
基本概念
Token 是一個自包含的憑證,包含使用者資訊和簽章,不需要伺服器儲存狀態。
JWT 結構
┌─────────────────────────────────────────────────────────┐
│ Header.Payload.Signature │
│ │
│ eyJhbGciOiJIUzI1NiJ9. ← Header │
│ eyJ1c2VySWQiOjEsIm5hbWUiOiJKb2huIn0. ← Payload │
│ SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV ← Signature │
└─────────────────────────────────────────────────────────┘
Token 使用流程
// 登入後取得 Token
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email, password })
});
const { token } = await response.json();
// 儲存 Token
localStorage.setItem('token', token);
// 後續請求帶上 Token
fetch('/api/profile', {
headers: {
'Authorization': `Bearer ${token}`
}
});Session vs Token
| 特性 | Session | Token (JWT) |
|---|---|---|
| 狀態儲存 | 伺服器 | 客戶端 |
| 擴展性 | 需同步 Session | 無狀態,易擴展 |
| 撤銷機制 | 刪除即失效 | 需黑名單機制 |
| 傳輸方式 | Cookie | Header |
| 安全性 | 較高 | 需注意儲存 |
LocalStorage & SessionStorage
使用方式
// LocalStorage - 永久儲存
localStorage.setItem('theme', 'dark');
localStorage.getItem('theme'); // 'dark'
localStorage.removeItem('theme');
// SessionStorage - 分頁關閉就清除
sessionStorage.setItem('tempData', JSON.stringify(data));
sessionStorage.getItem('tempData');適用場景
| 儲存方式 | 適用場景 |
|---|---|
| LocalStorage | 使用者偏好設定、暫存草稿 |
| SessionStorage | 表單暫存、分頁間不共享的資料 |
| Cookie | 認證資訊、追蹤用途 |
安全性考量
XSS 防護
// ❌ 不安全:Token 存 LocalStorage
localStorage.setItem('token', token);
// XSS 攻擊可以輕易竊取
// ✅ 較安全:Token 存 HttpOnly Cookie
// JavaScript 無法存取CSRF 防護
// ✅ 使用 SameSite Cookie
Set-Cookie: session=abc; SameSite=Strict
// ✅ 使用 CSRF Token
<form>
<input type="hidden" name="_csrf" value="random_token">
</form>實務建議
認證資訊儲存選擇:
安全性優先(推薦)
└─ HttpOnly Cookie + Session
└─ 伺服器端驗證
└─ 自動過期
└─ 防 XSS
可擴展性優先
└─ JWT Token
└─ 存在 HttpOnly Cookie(推薦)
└─ 或 Memory + Refresh Token
└─ 避免存 LocalStorage
一般資料
└─ 需持久化 → LocalStorage
└─ 僅當前分頁 → SessionStorage
└─ 小資料/需自動傳送 → Cookie