Cookies的SameSite屬性


自Chrome 51版本開始,瀏覽器的 Cookies 新增了一個SameSite屬性,用來防止 CSRF 攻擊和信息泄漏,更多信息參考chrome Feature: 'SameSite' cookie attribute

簡單回顧什么是CSRF攻擊

Cookies往往用來存儲用戶的身份信息,惡意網站通過設法偽造帶有正確Cookies進行 HTTP 請求,這就是 CSRF 攻擊。

舉例來說,用戶登陸了銀行網站your-bank.com,銀行服務器發來了一個 Cookie。

Set-Cookie: session_id=abc123;

用戶后來又訪問了惡意網站malicious-site.com,惡意網站總是想方設法讓你在惡意站點發送一個表單請求。

手段:中獎填寫聯系信息、透明的form表單提交按鈕、附加在誘惑圖片上的超鏈接

<form action="your-bank.com/transfer" method="POST">
  ...
</form>

用戶一旦被誘騙發送這個表單,銀行網站就會收到帶有正確 Cookie 的請求。為了防止CSRF攻擊,銀行網站表單會設置一個隱藏域,表單提交時一起帶上一個隨機token至服務器,告訴服務器這是真實請求。

<form action="your-bank.com/transfer" method="POST">
  <input type="hidden" name="token" value="dad3weg34">
  ...
</form>

之所以被CSRF攻擊,是因為惡意網站誘導你在其頁面上發送了第三方cookie(此時的銀行網站cookie為第三方cookie),它除了用於 CSRF 攻擊,還可以用於用戶追蹤。

第三方是一種相對概念,規定假定你正在訪問的站點為第一方站點,則瀏覽器為第二方,其他網站就是第三方站點,第三方站點誘導你發送第一方站點的cookie時,我們就說此時的cookie為第三方cookie。

比如,Facebook 在第三方網站插入一張看不見的圖片。

<img src="facebook.com" style="visibility:hidden;">

瀏覽器加載上面代碼時,就會向 Facebook 發出帶有 Cookie 的請求,從而 Facebook 就會知道你是誰,訪問了什么網站。

SameSite

cookies機制一直被認為是不安全的,隨着技術的更新,界內一直在完善cookies的安全機制,SameSite屬性是谷歌瀏覽器為完善cookies安全機制出的特性之一。

Cookie 的SameSite屬性用來限制第三方 Cookie的行為。

它可以設置三個值。

  • Strict
  • Lax
  • None

Strict

Strict最為嚴格,完全禁止第三方 Cookie,當當前站點與請求目標站點是跨站關系時,總是不會發送 Cookie。換言之,只有當前站點 與請求目標站點是同站關系時,才會帶上 Cookie。

Set-Cookie: CookieName=CookieValue; SameSite=Strict;

這個規則過於嚴格,可能造成非常不好的用戶體驗。

舉例說明:

假定你當前所處站點地址為https://obmq.com/index.html,該站需要通過XHR請求獲取某天氣站點的未來7天的天氣信息https://weather-forecast.org/api/weather?future=7,該接口要求必須攜帶cookieSet-Cookie: vip=true; Path=/; HttpOnly; SameSite=Strict;,這種情況下,你無論如何都無法在https://obmq.com站點下發送這個XHR請求時還能攜帶上這個cookie,換句話說,你發送的接口請求的cookie請求頭一定不會有vip=true,即使你現在已經是該天氣網站的vip。

None

None在Chrome 85 版本之前是SameSite的默認設置值,即Set-Cookie: key=value; SameSite=None等於Set-Cookie: key=value

在Chrome 85 版本之前,顯示設置SameSite=None不需要設置Secure屬性,詳細參見:Reject insecure SameSite=None cookies

在Chrome 85 版本以后,站點選擇顯式關閉SameSite屬性時,在將其值設為None的同時。必須同時設置Secure屬性(表示Cookie 只能通過 HTTPS 協議發送),否則無效。

下面的設置有效。

Set-Cookie: widget_session=abc123; SameSite=None; Secure

下面的設置無效。

Set-Cookie: widget_session=abc123; SameSite=None

Lax

Chrome 在85版本后將Lax設為SameSite的默認值,即Set-Cookie: key=value; SameSite=Lax等於Set-Cookie: key=value,詳細參見:Cookies default to SameSite=Lax

Lax規則比較寬松,大多數情況也不發送第三方 Cookie,但是導航到目標站點的 Get 請求除外。

Set-Cookie: CookieName=CookieValue; SameSite=Lax;

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

請求類型 示例 SameSite=None;Secure 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 不發送
xhr/fetch $.get("...") 發送 Cookie 不發送
Image <img src="..."> 發送 Cookie 不發送
Script <script src="..."> 發送Cookie 不發送

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

Schemeful Same-Site

自Chrome 86版本開始,考慮到不安全的http://協議仍然為網絡攻擊者提供了篡改cookie的機會,然后將這些cookie用於站點安全的https://。谷歌瀏覽器修改了cookie的Same Site的定義,將在相同域名的安全(https://)協議和不安全(http://)協議作為是否跨站的判斷因素之一。詳情參見Feature: Schemeful same-site

如果您的站點全面升級到https協議,那么下面的內容不適合您;如果您的站點是https協議和http協議混存,那么您需要關注。

常見的 "cross-scheme" Cookies攜帶情況

超鏈接

Schemeful Same-Site禁止時,從http:// site.example鏈接到https😕/site.example時,即使SameSite=Strict依然會攜帶上cookie。

Schemeful Same-Site啟用時,從http:// site.example鏈接到https😕/site.example時,SameSite=Strict的cookies會被鎖定,其他cookies攜帶的表現如下圖和下表:

Cross-scheme navigation from HTTP to HTTPS.

HTTP → HTTPS HTTPS → HTTP
SameSite=Strict ⛔ Blocked ⛔ Blocked
SameSite=Lax ✓ Allowed ✓ Allowed
SameSite=None;Secure ✓ Allowed ⛔ Blocked
加載子資源

加載子資源的方式包括images, iframes, 和XHR or Fetch的網絡請求。

加載子資源分為http加載https子資源https加載子http資源,攜帶cookies的表現如下圖和下表:

Schemeful Same-Site禁止時,加載子資源時,SameSite=Strict 或者SameSite=Lax的cookie會被攜帶上。

Schemeful Same-Site啟用時,加載子資源時,SameSite=Strict或者SameSite=Lax的cookies會被鎖定,其他cookies攜帶的表現如下圖和下表:

An HTTP page including a cross-scheme subresource via HTTPS.

HTTP → HTTPS HTTPS → HTTP
SameSite=Strict ⛔ Blocked ⛔ Blocked
SameSite=Lax ⛔ Blocked ⛔ Blocked
SameSite=None;Secure ✓ Allowed ⛔ Blocked
POST 表單

Schemeful Same-Site禁止時,發送POST表單時,SameSite=Strict 或者SameSite=Lax的cookie會被攜帶上。

Schemeful Same-Site啟用時,發送POST表單時,只有SameSite=None的cookies會被攜帶,其他cookies攜帶的表現如下圖和下表:

Cross-scheme form submission from HTTP to HTTPS.

HTTP → HTTPS HTTPS → HTTP
SameSite=Strict ⛔ Blocked ⛔ Blocked
SameSite=Lax ⛔ Blocked ⛔ Blocked
SameSite=None;Secure ✓ Allowed ⛔ Blocked
對WebSockets的影響?

如果WebSocket連接與頁面的安全性相同,則仍將被視為同站。

https://連接wss://被視為同站;http://連接ws://被視為同站,否則視為跨站。詳細如下:

Same-site:

  • wss://https:// 連接
  • ws://http:// 連接

Cross-site:

  • wss://http:// 連接
  • ws://https:// 連接

最佳實踐

依然使用token機制防止CSRF攻擊

設置了SameSite屬性值為StrictLax以后,基本杜絕了 CSRF 攻擊。但是SameSite是Cookies屬性之一,所以存在以下諸多限制:

  • 要求瀏覽器必須兼容Cookies的SameSite屬性

  • 要求客戶端應用必須支持Cookies機制,比如APP和微信小程序並不支持Cookies

限制如上所列,但不限於所列。

因為SameSite屬性存在以上限制,所以需要服務器端依然采用token機制來防止CSRF攻擊。

顯示指定SameSite屬性值為LaxStrict

總應該設置一個顯式的SameSite屬性,而不是依賴瀏覽器為您應用的默認設置。這使您對Cookie的使用意圖更加明確,並提高了跨瀏覽器獲得一致體驗的機會。

不兼容的客戶端的處理

對於SameSite屬性的兼容性在不同瀏覽器和相同瀏覽器的不同版本之間是不同的,可以參考chromium.org上的更新頁面的已知的不兼容客戶端以了解當前已知的問題,但是無法確定是否詳盡無遺。 盡管這不是理想的選擇,但可以在此過渡階段中采用一些解決方法。

方式一:同時設置兼容SameSite屬性的客戶端和不兼容SameSite屬性的客戶端

// ~ 同時設置兼容SameSite屬性的客戶端和不兼容SameSite屬性的客戶端

// ~ 對於兼容SameSite屬性的客戶端,顯示指定SameSite屬性值以明確使用意圖
Set-cookie: 3pcookie=value; SameSite=None; Secure

// ~ 對於不兼容SameSite屬性的客戶端,不設置SameSite屬性
Set-cookie: 3pcookie-legacy=value; Secure

下面的示例顯示了如何使用Express框架及其cookie-parser中間件在Node.js中執行此操作。

const express = require('express');
const cp = require('cookie-parser');
const app = express();
app.use(cp());

app.get('/set', (req, res) => {
  // Set the new style cookie
  res.cookie('3pcookie', 'value', { sameSite: 'none', secure: true });
  // And set the same value in the legacy cookie
  res.cookie('3pcookie-legacy', 'value', { secure: true });
  res.end();
});

app.get('/', (req, res) => {
  let cookieVal = null;

  if (req.cookies['3pcookie']) {
    // check the new style cookie first
    cookieVal = req.cookies['3pcookie'];
  } else if (req.cookies['3pcookie-legacy']) {
    // otherwise fall back to the legacy cookie
    cookieVal = req.cookies['3pcookie-legacy'];
  }

  res.end();
});

app.listen(process.env.PORT);

方式二:判斷客戶端的user-agent

在發送Set-Cookie相應頭時,您可以選擇通過user-agent字符串檢測客戶端。請參閱不兼容客戶端的列表,建議您找一個工具庫來處理user-agent,因為您很可能不想自己編寫這些正則表達式。

這種方法的好處在於,它只需要在設置cookie時進行一次更改即可。 但是,此處必須指出是user-agent嗅探本身是不可靠的,並且可能無法捕獲所有受影響的用戶。

無論選擇哪種方式,建議確保有一種記錄低版本客戶端比例的方法。 一旦比例下降到網站可接受的閾值以下,請確保您有提醒或警報以刪除此替代方法。

谷歌計划推出"Privacy Sandbox"

谷歌計划完全禁止第三方cookie,畢竟cookie真的不是很安全,詳細參考this

參考鏈接


文章同步發布在各大主流知識共享平台,所以設github為統一的反饋區

疑問、討論、問題反饋:https://github.com/weixsun/discussion


關注微信公眾號 obmq 及時了解最新動態


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM