預測最近面試會考 Cookie 的 SameSite 屬性

前言

2 月份發佈的 Chrome 80 版本中默認屏蔽了第三方的 Cookie,在灰度期間,就致使了阿里系的不少應用都產生了問題,爲此還專門成立了小組,推進各 BU 進行改造,目前阿里系基本已經改造完成。全部的前端團隊估計都收到過通知,也着實加深了一把你們對於 Cookie 的理解,因此極可能就此出個面試題,而即使不是面試題,當問到 HTTP 相關內容的時候,不妨也扯到這件事情來,一能代表你對前端時事的跟進,二還能借此引伸到前端安全方面的內容,爲你的面試加分。前端

因此本文就給你們介紹一下瀏覽器的 Cookie 以及這個"火熱"的 SameSite 屬性。git

HTTP

通常咱們都會說 「HTTP 是一個無狀態的協議」,不過要注意這裏的 HTTP 實際上是指 HTTP 1.x,而所謂無狀態協議,簡單的理解就是即便同一個客戶端連續兩次發送請求給服務器,服務器也識別不出這是同一個客戶端發送的請求,這致使的問題就好比你加了一個商品到購物車中,但由於識別不出是同一個客戶端,你刷新下頁面就沒有了……github

Cookie

爲了解決 HTTP 無狀態致使的問題,後來出現了 Cookie。不過這樣說可能會讓你產生一些誤解,首先無狀態並非很差,有優勢,但也會致使一些問題。而 Cookie 的存在也不是爲了解決通信協議無狀態的問題,只是爲了解決客戶端與服務端會話狀態的問題,這個狀態是指後端服務的狀態而非通信協議的狀態。web

Cookie 介紹

那咱們來看下 Cookie,引用下維基百科:面試

Cookie(複數形態Cookies),類型爲「小型文本文件」,指某些網站爲了辨別用戶身份而儲存在用戶本地終端上的數據。

做爲一段通常不超過 4KB 的小型文本數據,它由一個名稱(Name)、一個值(Value)和其它幾個用於控制 Cookie 有效期、安全性、使用範圍的可選屬性組成,這些涉及的屬性咱們會在後面會介紹。sql

Cookie 的查看

咱們能夠在瀏覽器的開發者工具中查看到當前頁面的 Cookie:數據庫

儘管咱們在瀏覽器裏查看到了 Cookie,這並不意味着 Cookie 文件只是存放在瀏覽器裏的。實際上,Cookies 相關的內容還能夠存在本地文件裏,就好比說 Mac 下的 Chrome,存放目錄就是~/Library/Application Support/Google/Chrome/Default,裏面會有一個名爲 Cookies 的數據庫文件,你可使用 sqlite 軟件打開它:json

存放在本地的好處就在於即便你關閉了瀏覽器,Cookie 依然能夠生效。後端

Cookie 的設置

那 Cookie 是怎麼設置的呢?簡單來講就是跨域

  1. 客戶端發送 HTTP 請求到服務器
  2. 當服務器收到 HTTP 請求時,在響應頭裏面添加一個 Set-Cookie 字段
  3. 瀏覽器收到響應後保存下 Cookie
  4. 以後對該服務器每一次請求中都經過 Cookie 字段將 Cookie 信息發送給服務器。

咱們以https://main.m.taobao.com/爲例來看下這個過程:

咱們在請求返回的 Response Headers 能夠看到 Set-Cookie 字段:

而後咱們查看下 Cookie:

咱們刷新一遍頁面,再看下這個請求,能夠在 Request Headers 看到 cookie 字段:

Cookies 的屬性

在下面這張圖裏咱們能夠看到 Cookies 相關的一些屬性:

這裏主要說一些你們可能沒有注意的點:

Name/Value

用 JavaScript 操做 Cookie 的時候注意對 Value 進行編碼處理。

Expires

Expires 用於設置 Cookie 的過時時間。好比:

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

當 Expires 屬性缺省時,表示是會話性 Cookie,像上圖 Expires 的值爲 Session,表示的就是會話性 Cookie。當爲會話性 Cookie 的時候,值保存在客戶端內存中,並在用戶關閉瀏覽器時失效。須要注意的是,有些瀏覽器提供了會話恢復功能,這種狀況下即便關閉了瀏覽器,會話期 Cookie 也會被保留下來,就好像瀏覽器歷來沒有關閉同樣。

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

Max-Age

Max-Age 用於設置在 Cookie 失效以前須要通過的秒數。好比:

Set-Cookie: id=a3fWa; Max-Age=604800;

Max-Age 能夠爲正數、負數、甚至是 0。

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

當 max-Age 屬性爲負數,則表示該 Cookie 只是一個會話性 Cookie。

當 max-Age 爲 0 時,則會當即刪除這個 Cookie。

假如 Expires 和 Max-Age 都存在,Max-Age 優先級更高。

Domain

Domain 指定了 Cookie 能夠送達的主機名。假如沒有指定,那麼默認值爲當前文檔訪問地址中的主機部分(可是不包含子域名)。

像淘寶首頁設置的 Domain 就是 .taobao.com,這樣不管是a.taobao.com仍是b.taobao.com均可以使用 Cookie。

在這裏注意的是,不能跨域設置 Cookie,好比阿里域名下的頁面把 Domain 設置成百度是無效的:

Set-Cookie: qwerty=219ffwef9w0f; Domain=baidu.com; Path=/; Expires=Wed, 30 Aug 2020 00:00:00 GMT

Path

Path 指定了一個 URL 路徑,這個路徑必須出如今要請求的資源的路徑中才能夠發送 Cookie 首部。好比設置Path=/docs/docs/Web/下的資源會帶 Cookie 首部,/test則不會攜帶 Cookie 首部。

Domain 和 Path 標識共同定義了 Cookie 的做用域:即 Cookie 應該發送給哪些 URL。

Secure屬性

標記爲 Secure 的 Cookie 只應經過被HTTPS協議加密過的請求發送給服務端。使用 HTTPS 安全協議,能夠保護 Cookie 在瀏覽器和 Web 服務器間的傳輸過程當中不被竊取和篡改。

HTTPOnly

設置 HTTPOnly 屬性能夠防止客戶端腳本經過 document.cookie 等方式訪問 Cookie,有助於避免 XSS 攻擊。

SameSite

SameSite 是最近很是值得一提的內容,由於 2 月份發佈的 Chrome80 版本中默認屏蔽了第三方的 Cookie,這會致使阿里系的不少應用都產生問題,爲此還專門成立了問題小組,推進各 BU 進行改造。

做用

咱們先來看看這個屬性的做用:

SameSite 屬性可讓 Cookie 在跨站請求時不會被髮送,從而能夠阻止跨站請求僞造攻擊(CSRF)。

屬性值

SameSite 能夠有下面三種值:

  1. Strict僅容許一方請求攜帶 Cookie,即瀏覽器將只發送相同站點請求的 Cookie,即當前網頁 URL 與請求目標 URL 徹底一致。
  2. Lax容許部分第三方請求攜帶 Cookie
  3. None不管是否跨站都會發送 Cookie

以前默認是 None 的,Chrome80 後默認是 Lax。

跨域和跨站

首先要理解的一點就是跨站和跨域是不一樣的。同站(same-site)/跨站(cross-site)」和第一方(first-party)/第三方(third-party)是等價的。可是與瀏覽器同源策略(SOP)中的「同源(same-origin)/跨域(cross-origin)」是徹底不一樣的概念。

同源策略的同源是指兩個 URL 的協議/主機名/端口一致。例如,https://www.taobao.com/pages/...,它的協議是 https,主機名是www.taobao.com,端口是 443。

同源策略做爲瀏覽器的安全基石,其「同源」判斷是比較嚴格的,相對而言,Cookie中的「同站」判斷就比較寬鬆:只要兩個 URL 的 eTLD+1 相同便可,不須要考慮協議和端口。其中,eTLD 表示有效頂級域名,註冊於 Mozilla 維護的公共後綴列表(Public Suffix List)中,例如,.com、.co.uk、.github.io 等。eTLD+1 則表示,有效頂級域名+二級域名,例如taobao.com等。

舉幾個例子,www.taobao.comwww.baidu.com是跨站,www.a.taobao.comwww.b.taobao.com是同站,a.github.iob.github.io是跨站(注意是跨站)。

改變

接下來看下從 None 改爲 Lax 到底影響了哪些地方的 Cookies 的發送?直接來一個圖表:

從上圖能夠看出,對大部分 web 應用而言,Post 表單,iframe,AJAX,Image 這四種狀況從之前的跨站會發送三方 Cookie,變成了不發送。

Post表單:應該的,學 CSRF 總會舉表單的例子。

iframe:iframe 嵌入的 web 應用有不少是跨站的,都會受到影響。

AJAX:可能會影響部分前端取值的行爲和結果。

Image:圖片通常放 CDN,大部分狀況不須要 Cookie,故影響有限。但若是引用了須要鑑權的圖片,可能會受到影響。

除了這些還有 script 的方式,這種方式也不會發送 Cookie,像淘寶的大部分請求都是 jsonp,若是涉及到跨站也有可能會被影響。

問題

咱們再看看會出現什麼的問題?舉幾個例子:

  1. 天貓和飛豬的頁面靠請求淘寶域名下的接口獲取登陸信息,因爲 Cookie 丟失,用戶沒法登陸,頁面還會誤判斷成是因爲用戶開啓了瀏覽器的「禁止第三方 Cookie」功能致使而給與錯誤的提示
  2. 淘寶部分頁面內嵌支付寶確認付款和確認收貨頁面、天貓內嵌淘寶的登陸頁面等,因爲 Cookie 失效,付款、登陸等操做都會失敗
  3. 阿里媽媽在各大網站好比今日頭條,網易,微博等投放的廣告,也是用 iframe 嵌入的,沒有了 Cookie,就不能準確的進行推薦
  4. 一些埋點系統會把用戶 id 信息埋到 Cookie 中,用於日誌上報,這種系統通常走的都是單獨的域名,與業務域名分開,因此也會受到影響。
  5. 一些用於防止惡意請求的系統,對判斷爲惡意請求的訪問會彈出驗證碼讓用戶進行安全驗證,經過安全驗證後會在請求所在域種一個Cookie,請求中帶上這個Cookie以後,短期內再也不彈安全驗證碼。在Chrome80以上若是由於Samesite的緣由請求沒辦法帶上這個Cookie,則會出現一直彈出驗證碼進行安全驗證。
  6. 天貓商家後臺請求了跨域的接口,由於沒有 Cookie,接口不會返回數據
  7. ……

若是不解決,影響的系統其實仍是不少的……

解決

解決方案就是設置 SameSite 爲 none。

以 Adobe 網站爲例:https://www.adobe.com/sea/,查看請求能夠看到:

不過也會有兩點要注意的地方:

  1. HTTP 接口不支持 SameSite=none

若是你想加 SameSite=none 屬性,那麼該 Cookie 就必須同時加上 Secure 屬性,表示只有在 HTTPS 協議下該 Cookie 纔會被髮送。

  1. 須要 UA 檢測,部分瀏覽器不能加 SameSite=none

IOS 12 的 Safari 以及老版本的一些 Chrome 會把 SameSite=none 識別成 SameSite=Strict,因此服務端必須在下發 Set-Cookie 響應頭時進行 User-Agent 檢測,對這些瀏覽器不下發 SameSite=none 屬性

Cookie 的做用

Cookie 主要用於如下三個方面:

  1. 會話狀態管理(如用戶登陸狀態、購物車、遊戲分數或其它須要記錄的信息)
  2. 個性化設置(如用戶自定義設置、主題等)
  3. 瀏覽器行爲跟蹤(如跟蹤分析用戶行爲等)

Cookie 的缺點

若是被問到話,能夠從大小、安全、增長請求大小等方面回答。

參考

  1. MDN
  2. HTTP是一個無狀態的協議。這句話裏的無狀態是什麼意思? - 靈劍的回答 - 知乎
  3. Chrome 80.0中將SameSite的默認值設爲Lax,對現有的Cookie使用有什麼影響? - 紫雲飛的回答 - 知乎
  4. 一些內部文章

各類系列

各類系列文章目錄地址:https://github.com/mqyqingfeng/Blog

若是有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。若是喜歡或者 有所啓發,歡迎 star,對做者也是一種鼓勵。

再其餘

21屆(大三或者研二)的同窗,要不要加入面試內推衝刺互助羣?各類福利活動,一對一簡歷輔導、各類進階指南、面試經驗、你說出你的面試題,還有淘系前端幫你寫答案 (是真的😂),歡迎掃碼入羣,買不了吃虧,買不了上當

相關文章
相關標籤/搜索