cookie和session是為了在無狀態的http協議之上維護會話狀態,使得伺服器可以知道當前是和哪個客戶在打交道。本文來詳細討論cookie和session的實現機制,以及其中涉及的安全問題。
因為http協議是無狀態的,即每次使用者請求到達伺服器時,http伺服器並不知道這個使用者是誰、是否登入過等。現在的伺服器之所以知道我們是否已經登入,是因為伺服器在登入時設定了瀏覽器的cookie!session則是借由cookie而實現的更高層的伺服器與瀏覽器之間的會話。
cookie是由網景公司的前雇員lou montulli在2023年發明的,現今cookie已經廣泛使用了。cookie是由客戶端儲存的小型文字檔案,其內容為一系列的鍵值對。 cookie是由http伺服器設定的,儲存在瀏覽器中, 在使用者訪問其他頁面時,會在http請求中附上該伺服器之前設定的cookie。 cookie的實現標準定義在rfc2109: http state management mechanism中。 那麼cookie是怎樣工作的呢?下面給出整個cookie的傳遞流程:
瀏覽器向某個url發起http請求(可以是任何請求,比如get乙個頁面、post乙個登入表單等)
對應的伺服器收到該http請求,並計算應當返回給瀏覽器的http響應。
http響應包括請求頭和請求體兩部分,可以參見:讀 http 協議。在響應頭加入
set-cookie
字段,它的值是要設定的cookie。
在rfc2109 6.3 implementation limits中提到: useragent(瀏覽器就是一種使用者**)至少應支援300項cookie, 每項至少應支援到4096位元組,每個網域名稱至少支援20項cookie。
瀏覽器收到來自伺服器的http響應。
瀏覽器在響應頭中發現set-cookie
字段,就會將該字段的值儲存在記憶體或者硬碟中。
set-cookie
欄位的值可以是很多項cookie,每一項都可以指定過期時間expires
。 預設的過期時間是使用者關閉瀏覽器時。
瀏覽器下次給該伺服器傳送http請求時, 會將伺服器設定的cookie附加在http請求的頭字段cookie
中。
瀏覽器可以儲存多個網域名稱下的cookie,但只傳送當前請求的網域名稱曾經指定的cookie, 這個網域名稱也可以在set-cookie
欄位中指定)。
伺服器收到這個http請求,發現請求頭中有cookie
字段, 便知道之前就和這個使用者打過交道了。
過期的cookie會被瀏覽器刪除。
總之,伺服器通過set-cookie
響應頭字段來指示瀏覽器儲存cookie, 瀏覽器通過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進行了篡改。乙個簡單的校驗過程可能是這樣的:
在伺服器中配置乙個不為人知的字串(我們叫它secret),比如:x$sfz32
。
當伺服器需要設定cookie時(比如authed=false
),不僅設定authed
的值為false
, 在值的後面進一步設定乙個簽名,最終設定的cookie是authed=false|6htibl7lvpd1p
。
簽名6htibl7lvpd1p
是這樣生成的:hash('x$sfz32'+'true')
。 要設定的值與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|***x
我不就知道true
的簽名是***x
了麼, 以後就可以用這個簽名來欺騙伺服器了。因此cookie中最好不要放敏感資料。 一般來講cookie中只會放乙個session id,而session儲存在伺服器端。
session 是儲存在伺服器端的,避免了在客戶端cookie中儲存敏感資料。 session 可以儲存在http伺服器的記憶體中,也可以存在記憶體資料庫(如redis)中, 對於重量級的應用甚至可以儲存在資料庫中。
我們以儲存在redis中的session為例,還是考察如何驗證使用者登入狀態的問題。
使用者提交包含使用者名稱和密碼的表單,傳送http請求。
伺服器驗證使用者發來的使用者名稱密碼。
如果正確則把當前使用者名稱(通常是使用者物件)儲存到redis中,並生成它在redis中的id。
這個id稱為session id,通過session id可以從redis中取出對應的使用者物件, 敏感資料(比如authed=true
)都儲存在這個使用者物件中。
設定cookie為sessionid=******|checksum
並傳送http響應, 仍然為每一項cookie都設定簽名。
使用者收到http響應後,便看不到任何敏感資料了。在此後的請求中傳送該cookie給伺服器。
伺服器收到此後的http請求後,發現cookie中有sessionid,進行放篡改驗證。
如果通過了驗證,根據該id從redis中取出對應的使用者物件, 檢視該物件的狀態並繼續執行業務邏輯。
web應用框架都會實現上述過程,在web應用中可以直接獲得當前使用者。 相當於在http協議之上,通過cookie實現了持久的會話。這個會話便稱為session。
cookie session(過時的寫法)
cookie存在客戶端的瀏覽器中,不太安全,容易被竊取,session被存在伺服器中 類似於字典中的value,伺服器會給瀏覽器返回這個value的key值,下次進來直接根據key取value.獲取表單資料 password request.post.get pwd print username,p...
Cookie,Session和Token的區別
在做介面測試時,經常會碰到請求引數為token的型別,但是可能大部分測試人員對token,cookie,session的區別還是一知半解。cookie cookie 是乙個非常具體的東西,指的就是瀏覽器裡面能永久儲存的一種資料,僅僅是瀏覽器實現的一種資料儲存功能。cookie由伺服器生成,傳送給瀏覽...
Cookie Session 的工作原理
cookie是一種伺服器通知瀏覽器,以鍵值對儲存的小量資訊的技術。瀏覽器向伺服器傳送請求 伺服器建立cookie物件,該cookie物件會攜帶使用者資訊,伺服器將該cookie物件傳送給瀏覽器。cookie儲存在瀏覽器端 以後瀏覽器再次向伺服器傳送請求時,會攜帶cookie物件 伺服器通過該cook...