有朋友看到這篇「 你知道 Cookie、LocalStorage、SessionStorage 的使用時機嗎? 」內容,對於
Token 不被 JS 存取,這件事情感到疑惑
正常來說,JavaScript 在瀏覽器上的行為”大部分”都是可以操作的,但是根據 MDN,在瀏覽器裡,「JavaScript 不被存取」通常指的就是把 Token 放在一個 帶有 HttpOnly 屬性的 Cookie 內。帶有這個屬性的 Cookie,瀏覽器在收到響應時會儲存它、並在每次發請求時自動附加,但JavaScript 卻永遠無法透過 document.cookie 讀取到它。這正是「Token 不被 JS 存取」的典型情境。
為什麼要使用 HttpOnly Cookie?
- 防範 XSS 攻擊 如果 Token(或 Session ID)存在於
localStorage
、sessionStorage
或一般 Cookie,任何注入到頁面的惡意腳本都可能透過 JavaScript 把它「讀」出來,再送給攻擊者;而 HttpOnly Cookie 一旦設置,JS 就完全無法碰它,大幅提高了對抗 XSS 的能力。 - 自動送出請求 帶有 HttpOnly(通常還會加上 Secure、SameSite)屬性的 Cookie,瀏覽器每次發同網域請求時都會自動夾帶,前端無需在程式裡手動把它放到
Authorization
header。
典型範例:Laravel Sanctum 的 SPA 模式
- 後端 在使用者登入成功後,透過 Set-Cookie: XSRF-TOKEN=…; HttpOnly; Secure; SameSite=Strict 發送一個 HttpOnly Cookie。
- 前端 只要在 axios/fetch 中設定 withCredentials: true,瀏覽器就會自動把這個 Cookie 附帶在後續所有 API 請求裡。
- JavaScript 完全無法讀取或篡改這個 Cookie,Token 保存在瀏覽器、卻對前端程式碼「隱身」。
就存取行為來討論,你想把後端做成 Stateless API,但又想沿用瀏覽器的 Cookie 機制(例如使用 Laravel Sanctum),或是當你最在意 XSS 風險,且不需要讓前端程式動態讀取 Token。
這時候就適合選用 HttpOnly Cookie
取捨、比較
儲存方式 | JS 是否可讀取 | 安全性 | 使用場景 |
---|---|---|---|
localStorage | 可 | 中 | 客製化操作(如前端自行插 header) |
一般 Cookie | 可 | 中 | 兼顧傳統 Session 或輕量追蹤 |
HttpOnly Cookie | 否 | 高(防 XSS) | 高安全性認證(如金鑰、Session ID、JWT) |
- 優點:防 XSS、瀏覽器代為傳送
- 缺點:無法由前端動態讀取、無法自己決定何時夾帶(必須用 cookie-based API)
回到「Token 不被 JS 存取」
這句話正是在描述「把認證 Token 存成 HttpOnly Cookie 的做法」,也就是:瀏覽器替你管理、JS 永遠拿不到,卻能在每次 API 呼叫時自動帶上,以達到更安全的認證流程。
實作步驟:
- 後端回應時設定 Set-Cookie: <你的 Token>=…; HttpOnly; Secure; SameSite=Strict
- 前端請求時帶上 withCredentials: true
- 後端驗證 Cookie 中的 Token,即完成安全的認證策略