一文了解cookie

@

什麼是Cookie?

Cookie 就是訪問者在訪問網站後留下的一個資訊片段。它存儲在客戶端(通常來說是瀏覽器)。你可以把cookie當作一個map,裡邊是鍵值對,每個鍵值對有過期時間路徑腳本可否訪問等描述資訊;描述資訊存儲在客戶端,客戶端請求時,默認會帶上cookie的名稱和值,不會帶描述資訊,通過http請求報文header中的cookie項進行傳輸;伺服器響應時,可以設置cookie資訊,就在http響應報文的headerSet-Cookie項。

那麼,它究竟有什麼作用呢?

眾所周知,HTTP 協議是無狀態的協議,如果你在同一個客戶端向伺服器發送多次請求,伺服器不會知道這些請求來自同一客戶端(同一個用戶)。

這樣有什麼好處呢?如果它是有狀態協議,你必須要時刻與伺服器建立鏈接,那麼如果連接意外斷開,整個會話就會丟失,重新連接之後一般需要從頭開始;而如果是無狀態協議,使得會話與連接本身獨立起來,這樣即使連接斷開了,會話狀態也不會受到嚴重傷害,保持會話也不需要保持連接本身。

但是,缺點也很明顯:即使同一個客戶端連續兩次發送請求給伺服器,伺服器也識別不出這是同一個客戶端發送的請求,這導致的問題就比如你加了一個商品到購物車中,但因為識別不出是同一個客戶端,你刷新下頁面就沒有了。

為了使伺服器知道每個請求具體來自於哪個用戶,比如你在逛淘寶的時候你只需要登錄一次,當你發起一次購買請求,伺服器就已經知道你登錄過了,不會再讓你進行登錄。

由此,Cookie誕生了,Cookie就是一種瀏覽器管理狀態的一個文件,讓無狀態的 HTTP 協議擁有一小塊記憶。

HTTP Cookie 機制是 HTTP 協議無狀態的一種補充和改良

Cookie 主要有以下用途:

  • 會話管理:登陸、購物車等應該記住的其他內容
  • 個性化:用戶偏好、主題或者其他設置

  • 追蹤:記錄和分析用戶行為

Cookie原理

第一次訪問網站的時候,瀏覽器發出請求,伺服器響應請求後,會將cookie放入到響應請求中(就在http響應報文的headerSet-Cookie項),在瀏覽器第二次發請求的時候,會把cookie帶過去(http請求報文header中的cookie項),服務端會辨別用戶身份,當然伺服器也可以修改cookie內容。

Set-Cookie 和 Cookie 標頭

Set-Cookie HTTP 響應標頭將 cookie 從伺服器發送到用戶代理。下面是一個發送 Cookie 的例子

在這裡插入圖片描述

隨著對伺服器的每個新請求,瀏覽器將使用 Cookie 頭將所有以前存儲的 Cookie 發送回伺服器。

在這裡插入圖片描述

Cookie的分類

有兩種類型的 Cookies,一種是 Session Cookies,一種是 Persistent Cookies,如果 Cookie 不包含到期日期,則將其視為會話 Cookie。會話 Cookie 存儲在記憶體中,永遠不會寫入磁碟,當瀏覽器關閉時,此後 Cookie 將永久丟失。如果 Cookie 包含有效期 ,則將其視為持久性 Cookie。在到期指定的日期,Cookie 將從磁碟中刪除。還有一種是 CookieSecureHttpOnly 標記,後面會介紹。

會話 Cookies

會話 Cookie 有個特徵,客戶端關閉時 Cookie 會刪除,因為它沒有指定ExpiresMax-Age 指令。

但是,Web 瀏覽器可能會使用會話還原,這會使大多數會話 Cookie 保持永久狀態,就像從未關閉過瀏覽器一樣。

例如:

在這裡插入圖片描述

永久性 Cookies

永久性 Cookie 不會在客戶端關閉時過期,而是在特定日期(Expires)特定時間長度(Max-Age)外過期。例如:

在這裡插入圖片描述

name

cookie的名字,一個域名下綁定的cookiename不能相同,相同的name的值會被覆蓋掉

value

value表示cookie的值

【注】JavaScript 操作 Cookie 的時候注意對 value 進行編碼處理。

Domain

這個代表的是,cookie綁定的域名,如果沒有設置,就會自動綁定到執行語句的當前域。由於同源策略,腳本只能訪問父域名或本域名的cookie(瀏覽器只能發送父域名或本域名的cookie),比如設置cookie域名為一級域名mydomain.com;那麼此域名下的二級域名www.mydomain.comimages.mydomain.com頁面,都可以訪問此cookie

【注】cookie區分域,而不區分埠,也就是說,同一個ip下的多個埠下的cookie是共享的!更確切的說,請求是會帶上同域下所有埠的cookie,但是返回時會覆蓋。

例如以下栗子:

在這裡插入圖片描述
在這裡插入圖片描述

Path

Path這個屬性默認是'/',這個值匹配的是web的路由

cookie是區分路徑的,也就是說,同一個鍵值對可以同時設置到 www.mydomain.com,www.mydomain.com/b下,並且是獨立的,互不影響的;如果不指定路徑,默認是當前路徑。

DomainPath 標識共同定義了 Cookie 的作用域:即 Cookie 應該發送給哪些 URL

Expires

Expires 用於設置 Cookie 的過期時間。當 Expires 屬性缺失時,表示是會話性 Cookie,值保存在客戶端記憶體中,並在用戶關閉瀏覽器時失效。需要注意的是,有些瀏覽器提供了會話恢復功能,這種情況下即使關閉了瀏覽器,會話期 Cookie 也會被保留下來,就好像瀏覽器從來沒有關閉一樣。

與會話性 Cookie 相對的是持久性 Cookie,持久性 Cookies 會保存在用戶的硬碟中,直至過期或者清除 Cookie。這裡值得注意的是,設定的日期和時間只與客戶端相關,而不是服務端。

所以如果你想要cookie存在一段時間,那麼你可以通過設置Expires屬性為未來的一個時間節點,Expires這個是代表當前時間的,然而這個屬性已經逐漸被Max-Age代替。

Max-Age

Max-Age 用於設置在 Cookie 失效之前需要經過的秒數。

Max-Age可以為正數、負數、甚至是 0。

  • Max-Age 屬性為正數時,瀏覽器會將其持久化,即寫到對應的 Cookie 文件中。

  • Max-Age 屬性為負數,則表示該 Cookie 只是一個會話性 Cookie

  • Max-Age 為 0 時,則會立即刪除這個 Cookie。因為cookie機制本身沒有設置刪除cookie,失效的cookie會被瀏覽器自動從記憶體中刪除,所以,它實現的就是讓cookie失效。

【注】假如 ExpiresMax-Age 都存在,Max-Age 優先順序更高。

Secure

由於http不僅是無狀態的,還是不安全的協議,容易被劫持。所以標記為 SecureCookie 只應通過被https協議加密過的請求發送給服務端。使用 https 安全協議,可以保護 Cookie 在瀏覽器和 Web 伺服器間的傳輸過程中不被竊取和篡改。

HTTPOnly

如果這個屬性設置為true,就不能通過js腳本來獲取cookie的值,能有效的防止xss攻擊。

SameSite

Chrome 51 開始,瀏覽器的 Cookie 新增加了一個SameSite屬性,用來防止 CSRF 攻擊和用戶追蹤。

CookieSameSite屬性可以設置三個值:

  • Strict
  • Lax
  • None

Strict

Strict最為嚴格,完全禁止第三方 Cookie,跨站點時,任何情況下都不會發送 Cookie。換言之,只有當前網頁的 URL 與請求目標一致,才會帶上 Cookie

這個規則過於嚴格,可能造成非常不好的用戶體驗。比如,當前網頁有一個 GitHub 鏈接,用戶點擊跳轉就不會帶有 GitHubCookie,跳轉過去總是未登陸狀態。

Lax

Lax規則稍稍放寬,大多數情況也是不發送第三方 Cookie,但是導航到目標網址的 Get 請求除外。

導航到目標網址的 GET 請求,只包括三種情況:鏈接,預載入請求,GET 表單。詳見下表。

請求類型 示例 正常情況 Lax
鏈接 <a href="..."></a> 發送 Cookie 發送 Cookie
預載入 <link rel="prerender" href="..."/> 發送 Cookie 發送 Cookie
GET 表單 <form method="GET" action="..."> 發送 Cookie 發送 Cookie
POST 表單 <form method="POST" action="..."> 發送 Cookie 不發送
iframe <iframe src="..."></iframe> 發送 Cookie 不發送
AJAX $.get("...") 發送 Cookie 不發送
Image <img src="..."> 發送 Cookie 不發送

設置了StrictLax以後,基本就杜絕了 CSRF 攻擊。當然,前提是用戶瀏覽器支援 SameSite 屬性。

None

Chrome 已將Lax變為默認設置。這時,網站可以選擇顯式關閉SameSite屬性,將其設為None。不過,前提是必須同時設置Secure屬性(Cookie 只能通過 https 協議發送),否則無效。

參考:

Tags: