Session
Last updated: Apr 3, 2026以下是 Session 的完整運作流程與實作細節:
1. 運作流程 (Workflow)
Session 的實作通常遵循以下四個步驟:
- 登入驗證:使用者提交帳密,伺服器驗證正確。
- 建立 Session:
- 伺服器在後端生成一個唯一的 Session ID(通常是長度隨機且不可預測的字串)。
- 伺服器將使用者的資訊(如
user_id,role)存入儲存媒介(如記憶體、Redis 或資料庫),並與該 ID 綁定。
- 發送 Cookie:伺服器透過 HTTP Header
Set-Cookie將 Session ID 傳給瀏覽器。 - 後續請求:瀏覽器之後發送請求時,會自動帶上這個 Cookie。伺服器拿到 ID 後去後端比對,確認是誰在操作。
2. 儲存媒介的選擇
實作時,Session 存放在哪裡至關重要:
- Memory (內存):最簡單(如 Express-session 預設),但伺服器重啟資料會消失,且無法跨伺服器共享。
- Redis / Memcached (推薦):最主流做法。速度極快,且支援設定 TTL (過期時間),適合分散式系統。
- Database (資料庫):最穩,但頻繁讀寫會對資料庫造成壓力。
3. 安全性的關鍵設定
實作 Session 時,Cookie 的設定是防禦攻擊的重中之重:
| 設定參數 | 說明 | 防禦的攻擊 |
|---|---|---|
| HttpOnly | 務必開啟。讓 JavaScript 無法讀取 Cookie。 | XSS (跨站腳本攻擊) |
| Secure | 規定 Cookie 只能在 HTTPS 連線下傳輸。 | 中間人攻擊 (攔截封包) |
| SameSite | 設定為 Lax 或 Strict。限制跨站請求攜帶 Cookie。 |
CSRF (跨站請求偽造) |
| Max-Age / Expires | 設定 Session 的有效期,避免永久有效。 | 降低設備遺失的風險 |
4. 程式碼範例 (Node.js + Express)
這是一個標準的實作範例,展示了如何配置安全的 Session:
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const { createClient } = require('redis');
// 1. 初始化 Redis 用於儲存 Session
let redisClient = createClient({ legacyMode: true });
redisClient.connect();
app.use(session({
store: new RedisStore({ client: redisClient }), // 儲存在 Redis
secret: 'your_super_secret_key', // 用來加密 Cookie 的金鑰
resave: false, // 若 Session 無變動不重新存儲
saveUninitialized: false, // 不要為未登入者建立空白 Session
cookie: {
httpOnly: true, // 防止 JS 讀取
secure: true, // 僅限 HTTPS (正式環境開啟)
sameSite: 'lax', // 防禦 CSRF
maxAge: 1000 * 60 * 30 // 30 分鐘後過期
}
}));
// 2. 登入成功後存入資料
app.post('/login', (req, res) => {
// 假設驗證成功
req.session.userId = 'user_123';
res.send('Logged in!');
});
5. 缺點與挑戰
雖然 Session 安全且易控,但在實作時需注意:
- 水平擴展 (Scaling):如果你有兩台伺服器,必須確保它們都能讀到同一個 Redis,否則 Load Balancer 把使用者導向 A 機,B 機卻沒資料。
- CSRF 防禦:Session 極度依賴 Cookie,因此除了
SameSite設定外,通常還需要額外的 CSRF Token 機制。
你想瞭解如何在分散式架構(例如多台伺服器)中具體設定 Redis 來管理 Session,還是想看看如何針對這個機制進行 CSRF 的防範測試?