你登入一個網站,關掉分頁,過幾分鐘再打開,帳號通常還在。你沒有重新輸入密碼,伺服器卻知道「這次 request 還是剛才那個人」。問題是,HTTP 本身並不會天然記住上一個 request 是誰送的;每一次 request 都可以被當成獨立事件。網站必須另外建立一套方法,把「前一次登入成功」這件事延續到後面的 request。
這時候最常一起出現的三個詞就是 Cookie、Session 和 Token。它們經常被放在同一張圖裡,久了很容易被理解成三種互相競爭的登入方案。其實不是。Cookie 比較像瀏覽器保存與傳送資料的機制;Session 是應用程式維持一段互動狀態的方式;Token 則是一個可以代表身分、權限或某種狀態的值。它們可以互相搭配,甚至同一套登入流程裡三個都會出現。
先記住這句:Cookie 是「怎麼帶東西」,Session 是「怎麼維持狀態」,Token 是「帶的那個值可能代表什麼」。
Cookie:瀏覽器幫你保存,之後符合條件就帶回去
Cookie 是 Web 平台的一部分。伺服器可以在 HTTP response 裡用 Set-Cookie header 要瀏覽器保存一個名稱和值;之後當瀏覽器向符合 domain、path、SameSite 等條件的網址送 request 時,會透過 Cookie header 把相關 cookie 帶回去。
Set-Cookie: session_id=abc123
之後的 browser request
Cookie: session_id=abc123
Cookie 本身不知道什麼叫「登入」。它可以拿來放 session ID,也可以記語言、介面偏好、購物車識別值或其他小型狀態。看到 Cookie,不代表你一定在做 authentication;反過來說,做登入也不代表一定只能靠 Cookie。
Session:伺服器記得「這一段互動屬於誰」
傳統網站很常採用 server-side session。當你輸入帳號密碼並通過驗證後,伺服器建立一筆 session 狀態,例如記住使用者 ID、登入時間、權限或其他暫時資訊,再產生一個難以猜測的 session ID。瀏覽器不需要拿到整筆 session 資料,只要保存這個 ID。
Server 建立 session:abc123 → user 42
Server → Set-Cookie: session_id=abc123
下一次 request
Browser → Cookie: session_id=abc123
Server 查 session store → 找到 user 42
OWASP 的 session management 指引強調,session ID 本身應該是沒有可讀業務意義、難以猜測的識別值。真正的 session 狀態通常由應用程式在伺服器端保存。這也是為什麼只看瀏覽器裡那串 session ID,通常不應該直接解得出「使用者是誰、是不是 admin」這類敏感資訊。
Token:一個能被系統拿來判斷身分或權限的值
Token 是更廣的概念。它可以是一串完全不透明、必須回伺服器查詢的隨機值,也可以是包含 claims 並經過簽章的結構化資料。OAuth 裡常見的 access token 就是一種 token;session ID 從很廣義的角度看,其實也可以被視為一種 token。
但工程實務講「token-based authentication」時,通常是在描述 client 拿到某個 credential,之後主動放進 request,例如:
Authorization: Bearer eyJ...
伺服器收到後,再驗證這個 token 是否有效、是否過期、是否有相應權限。OAuth 的 Bearer Token 規格裡,「bearer」的意思很直接:只要持有有效 token,就可能有能力使用它代表的權限,所以 token 洩漏本身就是安全事件。
Cookie 和 Token 不是二選一
網路上很常看到「Cookie vs Token」的比較,彷彿選了 token 就不能用 cookie。這其實把不同層次混在一起了。Token 可以被放在 Cookie 裡。例如伺服器簽發一個 authentication token,再用 Set-Cookie 交給瀏覽器保存;瀏覽器之後自動把它帶回去。也可以不放 cookie,而由 App 自己保存 token,再放進 Authorization header。
所以真正要問的通常不是「Cookie 還是 Token」,而是:憑證是什麼?存在哪裡?誰能讀到?request 時怎麼送?伺服器怎麼驗證?怎麼過期、撤銷和登出?
Session 也不等於「有狀態」,Token 也不保證「無狀態」
另一個常見口訣是「Session 是 stateful、Token 是 stateless」。它只能描述某些常見架構,不能當成定義。典型的 server-side session 確實需要伺服器保存 session state;某些自包含 token 則可以只靠簽章和 claims 驗證,不必每次查 session table。
但 token 系統仍然可能保存 server-side state,例如 refresh token 記錄、撤銷清單、裝置 session、風險狀態或 token family。反過來說,session 也不一定只存在單一伺服器記憶體裡,可以放在共享資料庫或 Redis。架構是不是 stateful,要看系統真正保存了哪些狀態,而不是看它叫 session 還是 token。
JWT 只是 Token 的一種格式
很多人第一次碰 token,是看到一長串以句點分成三段的 JWT。JWT 可以攜帶 claims,並透過簽章讓接收端檢查內容是否被竄改,但JWT 不等於 Token,Token 也不等於 JWT。一個完全隨機的 opaque token 一樣可以很好用;而 JWT 也不是因為「看起來有加密」就可以塞秘密資料。很多 JWT 只是編碼加簽,不代表 payload 對持有者不可讀。
更重要的是,選 JWT 不會自動替你解決登出、撤銷、權限更新與 token 竊取。這些仍然是系統設計問題。
HttpOnly、Secure、SameSite 到底保護什麼?
如果 authentication credential 放在 cookie 裡,幾個屬性很重要。HttpOnly 可以阻止一般前端 JavaScript 透過 document.cookie 直接讀取該 cookie;Secure 要求 cookie 只透過 HTTPS 傳送;SameSite 則控制 cookie 在跨站情境下是否會被帶上,能降低一部分 CSRF 風險。
但不要把任何一個屬性當成萬靈丹。HttpOnly 不代表 XSS 完全沒事,因為惡意腳本仍可能在你的頁面上發 request;SameSite 也不代表 CSRF 防護可以全部省略。安全通常是多層一起做:HTTPS、正確的 cookie 屬性、CSRF 防護、輸出轉義與 CSP、短效憑證、權限檢查、session rotation,以及適當的登出與撤銷機制。
為什麼 Cookie 常讓人想到 CSRF,而 JavaScript 可讀 Token 常讓人想到 XSS?
差異來自瀏覽器的行為。符合條件時,Cookie 會由瀏覽器自動附到 request 上,因此攻擊者可能嘗試誘使已登入使用者的瀏覽器送出不想要的 request,這就是 CSRF 類問題需要處理的原因之一。另一方面,如果敏感 token 被保存在可被頁面 JavaScript 讀取的位置,XSS 一旦成功,攻擊腳本就可能直接把 token 讀走並送到外部。
這不表示「Cookie 一定安全、localStorage 一定危險」,也不表示反過來。真正風險要看應用架構、瀏覽器行為、token 壽命、是否使用 HttpOnly、是否需要跨站請求,以及整體 XSS / CSRF 防禦。用一句口號替代 threat model,通常會把問題想得太簡單。
登出到底是在刪 Cookie,還是在讓 Session / Token 失效?
好的登出通常不只是把畫面切回登入頁。如果使用 server-side session,後端應讓那筆 session 失效,再讓瀏覽器端 cookie 過期。若系統使用可撤銷 token,也可能需要在伺服器端撤銷 refresh token、session record 或其他長期憑證。
只刪瀏覽器裡的 cookie,最多代表「這個瀏覽器之後不再自動帶它」;如果那個 credential 已被別人複製走,而伺服器端仍然接受,它可能還是能用。反過來,如果 server 已經把 session invalidated,就算舊 cookie 還留在瀏覽器裡,下一次送回去也應該被拒絕。
所以網站到底怎麼知道你已經登入?
答案不是「因為有 Cookie」,也不是「因為用了 Token」。比較完整的說法是:你第一次完成 authentication 後,系統發給 client 一個之後可以再次辨識或驗證你的 credential;client 在後續 request 裡把它帶回來,server 驗證成功後,才把這次 request 和你的帳號、權限與狀態連起來。
之後:request + credential → server 驗證 → 找到身分/權限 → 處理 request
在瀏覽器網站裡,這個 credential 很可能透過 cookie 傳送;在行動 App、CLI 或 API client 裡,也很常放在 Authorization header。你看到的是「保持登入」,系統真正做的則是反覆回答同一個問題:這次 request 帶來的憑證,現在還能不能代表這個使用者?
Cookie、Session、Token 最容易懂的方法,不是把它們排成三種登入技術,而是分層看:Cookie 管傳送與保存,Session 管連續狀態,Token 管可被驗證的憑證或識別值。分清楚這三層,很多登入架構突然就不神祕了。
資料來源
Cookie 行為與安全屬性參考 MDN:Set-Cookie 與 MDN:Secure cookie configuration;session ID 與 session management 參考 OWASP Session Management Cheat Sheet;Bearer token 定義參考 RFC 6750。