天天看點

HTTP系列-Cookie篇

通過閱讀本篇文章你可以學習到:

Cookie概念

産生原因

關于Cookie的首部字段

互動流程

生命周期

作用域

安全性

實際的用處

缺點

概念:通過在請求和響應封包中寫入Cookie資訊來控制用戶端的狀态,解決HTTP無狀态的問題,本質就是存儲在浏覽器上一個很小的文本檔案(也可能存在本地檔案裡)

HTTP是一種無狀态協定,沒法儲存之前請求響應的上下文資訊,但是對于一些場景來說需要用到之前的狀态,是以為了解決這個問題産生了Cookie。但是它并不是為了解決通訊協定無狀态的問題,而是為了解決用戶端與服務端會話狀态的問題,這個狀态是指後段服務的狀态而不是通訊協定的狀态。

關于Cookie的首部字段其實不太多,主要為:

<code>Set-Cookie</code>

<code>Cookie</code>

作用:在響應封包首部設定要傳遞給用戶端的Cookie資訊

例如:

作用:用戶端傳遞給服務端的Cookie資訊

用戶端和伺服器關于<code>Cookie</code>的互動流程如下:

用戶端請求服務端

服務端生成Cookie資訊使用 Set-Cookie 添加到響應封包頭部上

用戶端在拿到之後儲存Cookie

在下次請求的時候通過把資訊寫入請求封包頭部Cookie字段中傳給服務端

光看上面????說的可能有點迷糊,讓我們結合一個實際的案例看看。

這裡就以<code>koa</code>來模拟一個背景的登入接口,下面的代碼主要做了四件事:

設定響應的一些公共首部字段

對每個請求做一些處理,例如登入接口則不驗證token

定義了一個名為<code>/api/corsname</code>的接口,用來擷取名字

定義了一個名為<code>/api/login</code>的接口,用來使用者登入,并設定<code>Cookie</code>

./server.js:

OK????,來看看用戶端(浏覽器端)調用這兩個接口的代碼:

./index.html:

此時,點選「登入」按鈕,可以在<code>/login</code>這個接口的響應體中看到<code>Set-Cookie</code>這個首部字段:

HTTP系列-Cookie篇

(圖裡紅色圈中的<code>Access-Control-Allow-Credentials: true</code>請忽略它,因為這張圖是另一篇文章中拿來的,是以重點是<code>Set-Cookie</code>)

登入成功之後,點選「擷取name」按鈕,可以在<code>/corsname</code>這個接口的請求體中看到<code>Cookie</code>這個首部字段:

HTTP系列-Cookie篇

再來看看在浏覽器中,我們可以如何檢視<code>Cookie</code>:

HTTP系列-Cookie篇

在上面有介紹到關于<code>Cookie</code>的首部字段主要是<code>Set-Cookie</code>和<code>Cookie</code>,那有關于<code>Cookie</code>生命周期的首部字段的屬性有哪些呢?也就是可以用什麼來控制<code>Cookie</code>的生命周期。

(其實有點類似于《霖呆呆你來說說浏覽器緩存吧》中提到的強緩存)

預設情況下<code>Cookie</code>是暫時存在的,也就是它們的存儲隻在浏覽器會話期間存在,當使用者在關閉浏覽器時失效

可以使用<code>expires</code>和<code>max-age</code>來設定<code>Cookie</code>的過期時間

作用:給<code>Cookie</code> 設定過期時間,一個具體的時間。

預設值:預設為設定的<code>expires</code>的目前時間。

案例:

例如後端代碼中:

此時接口請求的響應體的首部字段帶有:

作用:給<code>Cookie</code>設定過期時間,一段時間,機關是秒,從用戶端收到封包開始計算。

預設值:<code>-1</code>。

使用方式與<code>expires</code>一樣:

另外,屬性值分為以下三種,友善記憶:

0:立即删除這個<code>Cookie</code>

正數:浏覽器将其持久化寫入<code>Cookie</code>中

負數:會話性<code>Cookie</code>

針對于上面????的三種情況,面試時可能會碰到的問題:

A:如果<code>max-age</code>為0,則表示删除該<code>cookie</code>。<code>cookie</code>機制沒有提供删除<code>cookie</code>的方法,是以通過設定該<code>cookie</code>即時失效實作删除<code>cookie</code>的效果。失效的<code>Cookie</code>會被浏覽器從<code>cookie</code>檔案或者記憶體中删除。

A:如果<code>max-age</code>屬性為正數,則表示該<code>cookie</code>會在<code>max-age</code>秒之後自動失效。浏覽器會将<code>max-age</code>為正數的<code>cookie</code>持久化,即寫到對應的<code>cookie</code>檔案中。無論客戶關閉了浏覽器還是電腦,隻要還在<code>max-age</code>秒之前,登入網站時該<code>cookie</code>仍然有效。

A:如果<code>max-age</code>為負數,則表示該<code>cookie</code>僅在本浏覽器視窗以及本視窗打開的子視窗内有效,關閉視窗後該<code>cookie</code>即失效。<code>max-age</code>為負數的<code>Cookie</code>,為臨時性<code>cookie</code>,不會被持久化,不會被寫到<code>cookie</code>檔案中。<code>cookie</code>資訊儲存在浏覽器記憶體中,是以關閉浏覽器該<code>cookie</code>就消失了。<code>cookie</code>預設的<code>max-age</code>值為<code>-1</code>。

作用域概念:對于<code>Cookie</code>的作用域,表示的是給<code>Cookie</code>綁定域名和路徑,在發送請求之前若是發現域名或者路徑這兩個屬性不比對則不會攜帶<code>Cookie</code>,通俗來說就是在哪些情況下攜帶<code>Cookie</code>。

有關于<code>Cookie</code>作用域的首部字段有哪些呢?

<code>domain=域名</code>

<code>path=PATH</code>

作用:指定<code>Cookie</code>可以送達的主機名。

作用:指定一個<code>URL</code>路徑,<code>Cookie</code>首部隻會被添加到這個指定<code>URL</code>路徑的請求封包首部上。

預設值為:<code>/</code>,也就是所有<code>URL</code>路徑都會攜帶<code>Cookie</code>。

例如設定了:

那麼隻有<code>/docs</code> 下的資源才會帶有<code>Cookie</code>,而另一個名為<code>/test</code> 的目錄下就沒有。

<code>Cookie</code>的安全性也是一個常問的點,這方面涉及到的首部字段的屬性主要有:

<code>Secure</code>

<code>HttpOnly</code>

<code>SameSite</code>

作用:設定了<code>secure</code>屬性,表示<code>Cookie</code>隻在<code>HTTPS</code>下傳輸。

讓我們來看一個實際的運用場景。

前提條件:https://lindaidai.com 對<code>cookie</code>設定了<code>secure=true</code>屬性。

通路 https://lindaidai.com

輸入使用者名、密碼,用<code>Chrome</code>的<code>developer tool</code>會看到<code>response</code>的<code>header</code>裡,<code>set-cookie</code>的值裡有<code>secure</code>屬性

登入後,繼續通路https://lindaidai.com/#user ,可以正常看到内容

修改url,通路http://lindaidai.com/#domain ,會跳轉到登入頁面,因為<code>cookie</code>在<code>http</code>協定下不發送給伺服器,伺服器要求使用者重新登入

作用:帶上<code>HttpOnly</code>的<code>Cookie</code>隻能通過HTTP協定傳輸,不能通過<code>JS</code>腳本檔案通路(<code>document.cookie</code>)。

由于設定了<code>HttpOnly</code>标志的<code>Cookie</code>隻能使用在<code>HTTP</code>請求過程中,而無法用<code>JS</code>腳本來讀取;又因為很多的<code>XSS</code>攻擊都是通過盜用<code>Cookie</code>的,是以設定<code>HttpOnly</code>屬性也能保護我們<code>Cookie</code>的安全,是一種預防<code>XSS</code>攻擊的重要手段吧。

作用:用來限制第三方<code>Cookie</code>,一般用來防止<code>CSRF</code>攻擊。

預設值:<code>Chrome80</code>之前一直是<code>None</code>,在<code>Chrome80</code>之後為<code>Lax</code>。

對于第一方<code>Cookie</code>和第三方<code>Cookie</code>我在這裡推薦一篇比較好的文章,值得靜下心來好好看:

《關于第一方Cookie和第三方Cookie你需要知道的》

兩種類型的<code>Cookie</code>:

第一方<code>Cookie</code>:由主機域(使用者正在通路的域),這些類型的Cookie通常被認為是不錯的。它們有助于提供更好的使用者體驗,并使會話保持打開狀态。基本上,這意味着浏覽器能夠記住關鍵資訊,例如您添加到購物車中的項目,使用者名和密碼以及語言首選項。

第三方<code>Cookie</code>:由使用者當時所通路的域以外的域建立的Cookie,主要用于跟蹤和線上廣告目的。它們還允許網站所有者提供某些服務,例如實時聊天。

第一方<code>Cookie</code>和第三方<code>Cookie</code>,都是網站在用戶端上存放的一小塊資料。他們都由某個域存放,隻能被這個域通路。他們的差別其實并不是技術上的差別,而是使用方式上的差別。

一個例子:

比如,通路A這個網站,這個網站設定了一個Cookie,這個Cookie也隻能被A這個域下的網頁讀取,這就是第一方Cookie。如果還是通路A這個網站,網頁裡有用到B網站(和A網站的域名是不同的)的一張圖檔,浏覽器在B請求圖檔的時候,B設定了一個Cookie,那這個Cookie隻能被B這個域通路,反而不能被A這個域通路,因為對我們來說,我們實際是在通路A網站時,被設定了一個B這個域下的Cookie,是以叫第三方Cookie。 (你我他;你:A網站,我:浏覽器,他:B網站;‘他’ 就是第三方,是以B網站下的cookie是第三方cookie。)

像上面的這個案例,在A網站中用到B網站的<code>Cookie</code>,如果這兩個網站不同站的話,就屬于<code>第三方Cookie跨站點使用</code>。

同站:隻要兩個URL的<code>eTLD+1</code>相同即為同站

其它例子:

同站:

跨站:

特殊的(下面這種情況是跨站):

在上面????已經介紹了有關于<code>SameSite</code>的作用,那麼具體是如何來控制第三方<code>Cookie</code>的呢?

實際上就是通過給<code>SameSite</code>設定不同的屬性值來控制的。

主要分為三種:

<code>Strict</code>

<code>Lax</code>

<code>None</code>

來看看具體的作用:

Strict:

最為嚴格,完全禁止第三方Cookie跨站點使用

也就是隻有網頁的URL和請求目标的URL一緻才會攜帶Cookie

Lax:

允許部分第三方請求攜帶<code>Cookie</code>。

也就是隻能允許 連結、預加載、GET表單 發送<code>Cookie</code>。

None:

無論是否跨站都會發送<code>Cookie</code>。

對于預設值,<code>Chrome80</code>之前一直是<code>None</code>,在<code>Chrome80</code>之後為<code>Lax</code>。

<code>HTTP</code>接口不支援<code>SameSite=None</code>,必須配合<code>Secure</code>屬性,表示隻有在<code>HTTPS</code>協定下才發送<code>Cookie</code>;

需要進行<code>UA</code>檢測,部分浏覽器不能加<code>SameSite=None</code>,<code>IOS12</code>的<code>Safari</code>以及老的<code>Chrome</code>浏覽器會把<code>SameSite=None</code>當成<code>Same=Strict</code>,是以需要用<code>User-Agent</code>擷取浏覽器資訊對一些浏覽器不下發<code>Cookie</code>

<code>Cookie</code>實際的用處其實非常多,主要有:

會話狀态管理(如使用者登入狀态、購物車、遊戲分數或其它需要記錄的資訊)

個性化設定(如使用者自定義設定、主題等)

浏覽器行為跟蹤(如跟蹤分析使用者行為等)

容量缺陷。Cookie 的體積上限隻有4KB,隻能用來存儲少量的資訊。

性能缺陷。Cookie 緊跟域名,不管域名下面的某一個位址需不需要這個 Cookie ,請求都會攜帶上完整的 Cookie,使得請求會攜帶不必要的參數。但是可以通過Domain和Path指定作用域來解決

安全缺陷。由于 Cookie 以純文字的形式在浏覽器和伺服器中傳遞,很容易被非法使用者截獲。在HttpOnly為false的情況下可以通過JS腳本擷取到。

最後,千言萬語彙成一張圖...

HTTP系列-Cookie篇

《極客時間-跨站腳本攻擊(XSS):為什麼Cookie中有HttpOnly屬性?》

《10種跨域解決方案(附終極大招)》