Web 筆記 - Cookie 與安全屬性
1. Cookie 基礎概念
1.1 為什麼需要理解 Cookie 機制
- Cookie 是網站存儲用戶狀態的主要方式,特別是身份驗證信息
- 不當的 Cookie 配置會導致多種安全漏洞(如 XSS、CSRF)
- 瀏覽器發送請求時會自動附加 Cookie,這是許多攻擊的基礎
1.2 讀/寫 Cookie 基礎
| 操作 | JavaScript 範例 | 說明 |
|---|---|---|
| 讀取整串 | document.cookie | 回傳 key=value; key2=value2 字串 |
| 解析為物件 | .split("; ").map(kv => kv.split("=")).reduce(...) | 手動轉成物件 |
| 讀取單一值 | getCookie("lang") | 封裝函式取值 |
| 寫入 Cookie | document.cookie = "theme=dark; path=/; max-age=604800" | 同名、同 path 即覆寫 |
| 設定 HttpOnly | ❌ JavaScript 無法設定 | 只能伺服器設定,JS 無法讀寫 |
1.3 為什麼不應透過 JavaScript 存取敏感 Cookie
- JavaScript 可被注入(XSS),導致攻擊者可讀取所有非 HttpOnly Cookie
- 前端 JS 通常不需要直接訪問敏感的身份驗證 Cookie(如 session)
- 敏感資訊應由伺服器處理,不暴露給客戶端
2. Cookie 安全屬性
2.1 HttpOnly 屬性
HttpOnly只能防止 JavaScript 讀取 Cookie,但不能防止覆寫- 主要用於防止 XSS 攻擊竊取敏感 Cookie(如 session)
- 伺服器端設定:
Set-Cookie: session=abc123; HttpOnly - 重要功能:標記為 HttpOnly 的 Cookie 對
document.cookieAPI 完全不可見
HttpOnly 的關鍵好處:
- 即使網站存在 XSS 漏洞,攻擊者也無法通過 JavaScript 直接獲取 session cookie
- 減少憑證被盜用的風險
- 為敏感 Cookie(如身份驗證)提供額外保護層
HttpOnly 擋不了覆寫:
- 攻擊者若能執行 JS,可用
document.cookie = "session=attacker_value"覆寫同名 Cookie - 覆寫成功後,下次發送請求時瀏覽器將附帶新的 session 值
- 需要配合其他安全措施共同防禦
2.2 SameSite 屬性
| SameSite 屬性 | 跨站請求是否附帶 Cookie | 常見用途 |
|---|---|---|
Strict | ❌ 不會附帶(包括 GET) | 最嚴格防禦 CSRF,需使用者從同一站點觸發互動 |
Lax | ✅ 附帶 GET,但不附帶 POST 等變更操作 | 預設值,適合大多數網站基本防禦需求 |
None | ✅ 完全附帶,但必須搭配 Secure | 第三方請求需附帶 Cookie(如第三方登入) |
2.3 Secure 屬性
- 確保 Cookie 只能通過 HTTPS 連接傳送
- 防止 Cookie 在不安全的連接中被竊取
- 當設置
SameSite=None時必須搭配Secure使用
3. 常見安全威脅與防禦
3.1 XSS 攻擊
未加 HttpOnly 的 XSS 範例
- 網站登入後回傳:
- 攻擊者留言內容:
- 使用者打開頁面時,自動執行 JS,將 Cookie 傳到攻擊者伺服器
- 攻擊者複製 Cookie,在自己瀏覽器中偽裝登入成功
XSS 防禦建議
- 為敏感 Cookie 設置
HttpOnly屬性 - 實施內容安全政策 (CSP)
- 對用戶輸入進行嚴格的驗證和轉義
3.2 CSRF 攻擊
即使有 HttpOnly 仍有 CSRF 風險
CSRF 攻擊利用瀏覽器自動附帶 Cookie:
- 使用者登入 bank.com,取得 Cookie:
session=abc123; HttpOnly - 造訪 evil.com,自動提交表單到 bank.com/transfer
- 瀏覽器自動帶上 session Cookie,完成未授權操作
關鍵: HttpOnly 防的是 XSS,不是 CSRF。
CSRF 攻擊程式碼範例
攻擊者在 evil.com 上放置的惡意頁面 (evil.html):
攻擊流程:
- 使用者已登入銀行網站,持有有效的 session cookie
- 使用者被誘導訪問 evil.com 或接收到含有惡意程式碼的電子郵件
- 頁面載入後自動提交表單到 bank.com/api/transfer
- 由於瀏覽器的同源政策,當向 bank.com 發送請求時,會帶上 bank.com 的 cookie
- bank.com 的伺服器看到有效的 session cookie,因此授權轉賬操作
CSRF 防禦建議
- 使用
SameSite=Lax或Strict屬性 - 實施 CSRF Token 機制
4. CSRF Token 實作方案
4.1 Synchronizer Token(同步式)
- Token 存在 Session 中,伺服器注入
<input type="hidden" name="csrf"> - 前端送出後,伺服器比對
req.session.csrfToken === req.body.csrf - 適合傳統多頁應用
4.2 Next.js 與 CSRF Token 整合範例 (Double Submit Cookie)
同步式 CSRF Token 是目前最安全的 CSRF 防護方式,以下提供一個使用 Next.js App Router 的完整實作範例。這個範例說明如何在現代 React 應用中實現 CSRF 保護:
1. Token 產生與儲存 (Server-Side)
2. 在表單頁面中注入 Token (Server Component)
3. API Endpoint 驗證 Token (Route Handler)
4.3 CSRF 防護實施關鍵點
- 整合性: CSRF 保護需要前後端協同工作,從 Token 生成到驗證
- 安全儲存: Token 必須存儲在 HttpOnly、SameSite=Strict 的 Cookie 中
- 一次性使用: 理想情況下,每次提交表單後應重新生成 Token(防止重放攻擊)
- 時間限制: 可考慮為 Token 加入過期時間,定期強制刷新
4.4 為何攻擊者無法偽造 CSRF Token?
- 同源政策: 攻擊網站無法讀取目標網站的 Cookie 或 DOM 內容
- HttpOnly: JavaScript 無法讀取標記為 HttpOnly 的 Cookie
- SameSite=Strict: 嚴格限制 Cookie 只在同一網站的請求中發送
注意: 若網站存在 XSS 漏洞,CSRF 保護可能被繞過,因為攻擊者可以通過 XSS 直接讀取頁面中的 Token。這也是為什麼 XSS 防護同樣重要的原因。
5. 綜合安全設定範例
建議:Session Cookie 使用
Lax,CSRF Token Cookie 使用Strict。
6. 安全實施建議小結
HttpOnly防止 XSS 偷 Cookie,無法防止 CSRF 自動送 Cookie- 最佳實務:
SameSite+ CSRF Token(同步式或雙重 Cookie)雙重防護 - 若有 XSS 風險,建議採用同步式 Token(由後端注入頁面)
- 關鍵敏感操作應增加額外驗證(如二次密碼、OTP)