Cookie和Session是為了在無狀態的HTTP協議之上維護會話狀態,使得服務器可以知道當前是和哪個客戶在打交道。本文來詳細討論Cookie和Session的實現機制,以及其中涉及的安全問題。
因為HTTP協議是無狀態的,即每次用戶請求到達服務器時,HTTP服務器並不知道這個用戶是誰、是否登錄過等。現在的服務器之所以知道我們是否已經登錄,是因為服務器在登錄時設置了瀏覽器的Cookie!Session則是借由Cookie而實現的更高層的服務器與瀏覽器之間的會話。
一、cookie安全隱患
Cookie提供了一種手段使得HTTP請求可以附加當前狀態, 現今的網站也是靠Cookie來標識用戶的登錄狀態的:
- 用戶提交用戶名和密碼的表單,這通常是一個POST HTTP請求。
- 服務器驗證用戶名與密碼,如果合法則返回200(OK)並設置 Set-Cookie 為 authed=true 。
- 瀏覽器存儲該Cookie。
- 瀏覽器發送請求時,設置
Cookie
字段為 authed=true 。 - 服務器收到第二次請求,從
Cookie
字段得知該用戶已經登錄。 按照已登錄用戶的權限來處理此次請求。
這里面的問題在哪里?
我們知道可以發送HTTP請求的不只是瀏覽器,很多HTTP客戶端軟件(包括curl、Node.js)都可以發送任意的HTTP請求,可以設置任何頭字段。 假如我們直接設置Cookie
字段為authed=true
並發送該HTTP請求, 服務器豈不是被欺騙了?這種攻擊非常容易,Cookie是可以被篡改的!
二、cookie防篡改機制
服務器可以為每個Cookie項生成簽名,由於用戶篡改Cookie后無法生成對應的簽名, 服務器便可以得知用戶對Cookie進行了篡改。一個簡單的校驗過程可能是這樣的:
- 在服務器中配置一個不為人知的字符串(我們叫它Secret),比如: x$sfz32 。
- 當服務器需要設置Cookie時(比如 authed=false ),不僅設置
authed
的值為false
, 在值的后面進一步設置一個簽名,最終設置的Cookie是 authed=false|6hTiBl7lVpd1P 。 - 簽名
6hTiBl7lVpd1P
是這樣生成的: Hash('x$sfz32'+'false') 。 要設置的值與Secret相加再取哈希。 - 用戶收到HTTP響應並發現頭字段 Set-Cookie: authed=false|6hTiBl7lVpd1P 。
- 用戶在發送HTTP請求時,篡改了
authed
值,設置頭字段 Cookie: authed=true|??? 。 因為用戶不知道Secret,無法生成簽名,只能隨便填一個。 - 服務器收到HTTP請求,發現 Cookie: authed=true|??? 。服務器開始進行校驗: Hash('true'+'x$sfz32') ,便會發現用戶提供的簽名不正確。
通過給Cookie添加簽名,使得服務器得以知道Cookie被篡改。然而故事並未結束。
因為Cookie是明文傳輸的, 只要服務器設置過一次 authed=true|xxxx 我不就知道true
的簽名是xxxx
了么, 以后就可以用這個簽名來欺騙服務器了。因此Cookie中最好不要放敏感數據。 一般來講Cookie中只會放一個Session Id,而Session存儲在服務器端。
-------------------------------------------------------------------------------------------
本文轉載自:http://harttle.land/2015/08/10/cookie-session.html