使用 HTTP Cookie

Cookie(也稱為網路 Cookie 或瀏覽器 Cookie)是伺服器傳送給使用者網路瀏覽器的一小段資料。瀏覽器可以儲存 Cookie、建立新 Cookie、修改現有 Cookie,並在後續請求中將其傳送回同一伺服器。Cookie 使網路應用程式能夠儲存有限數量的資料並記住狀態資訊;預設情況下,HTTP 協議是無狀態的

在本文中,我們將探討 Cookie 的主要用途,解釋使用它們的最佳實踐,並審視它們對隱私和安全的影響。

Cookie 的用途

通常,伺服器會使用 HTTP Cookie 的內容來確定不同請求是否來自同一個瀏覽器/使用者,然後酌情發出個性化或通用響應。以下描述了一個基本的用​​戶登入系統:

  1. 使用者向伺服器傳送登入憑據,例如透過表單提交。
  2. 如果憑據正確,伺服器會更新 UI 以指示使用者已登入,並返回一個包含會話 ID 的 Cookie,該 Cookie 會記錄使用者在瀏覽器上的登入狀態。
  3. 稍後,使用者導航到同一網站上的另一個頁面。瀏覽器會隨相應的請求一起傳送包含會話 ID 的 Cookie,以表明它仍然認為使用者已登入。
  4. 伺服器檢查會話 ID,如果仍然有效,則向用戶傳送新頁面的個性化版本。如果無效,則刪除會話 ID,並向用戶顯示該頁面的通用版本(或者顯示“拒絕訪問”訊息並要求重新登入)。

visual representation of the above sign-in system description

Cookie 主要用於三個目的:

  • 會話管理:使用者登入狀態、購物車內容、遊戲分數或伺服器需要記住的任何其他與使用者會話相關的詳細資訊。
  • 個性化:使用者偏好,例如顯示語言和 UI 主題。
  • 跟蹤:記錄和分析使用者行為。

資料儲存

在網路早期沒有其他選擇時,Cookie 被用於一般客戶端資料儲存目的。現在推薦使用現代儲存 API,例如Web Storage API (localStoragesessionStorage) 和IndexedDB

它們在設計時就考慮到了儲存,從不向伺服器傳送資料,並且沒有使用 Cookie 進行儲存的其他缺點:

  • 瀏覽器通常限制每個域的最大 Cookie 數量(因瀏覽器而異,通常為數百個)和每個 Cookie 的最大大小(通常為 4KB)。儲存 API 可以儲存更多資料。
  • Cookie 會隨每個請求傳送,因此它們可能會降低效能(例如在緩慢的移動資料連線上),尤其是當您設定了大量 Cookie 時。

注意:要檢視儲存的 Cookie(以及網頁正在使用的其他儲存),您可以使用 Firefox 開發者工具中的儲存檢查器,或 Chrome 開發者工具中的應用程式面板

建立、移除和更新 Cookie

收到 HTTP 請求後,伺服器可以透過響應傳送一個或多個Set-Cookie 標頭,每個標頭都會設定一個單獨的 Cookie。Cookie 透過指定一個名稱-值對來設定,如下所示:

http
Set-Cookie: <cookie-name>=<cookie-value>

以下 HTTP 響應指示接收瀏覽器儲存一對 Cookie:

http
HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: yummy_cookie=chocolate
Set-Cookie: tasty_cookie=strawberry

[page content]

注意:瞭解如何在各種伺服器端語言/框架中使用 Set-Cookie 標頭:PHPNode.jsPythonRuby on Rails

發出新請求時,瀏覽器通常會在Cookie HTTP 標頭中將先前儲存的當前域的 Cookie 傳送回伺服器:

http
GET /sample_page.html HTTP/2.0
Host: www.example.org
Cookie: yummy_cookie=chocolate; tasty_cookie=strawberry

您可以指定一個過期日期或時間段,在此之後 Cookie 應被刪除且不再發送。根據建立 Cookie 時Set-Cookie 標頭中設定的屬性,它們可以是永久會話Cookie:

  • 永久 Cookie 在 Expires 屬性中指定的日期之後刪除

    http
    Set-Cookie: id=a3fWa; Expires=Thu, 31 Oct 2021 07:28:00 GMT;
    

    或在 Max-Age 屬性中指定的期限之後刪除

    http
    Set-Cookie: id=a3fWa; Max-Age=2592000
    

    注意:Expires 的可用時間比 Max-Age 長,但是 Max-Age 更不容易出錯,並且在兩者都設定時具有優先權。其原理是,當您設定 Expires 日期和時間時,它們是相對於設定 Cookie 的客戶端而言的。如果伺服器設定為不同的時間,這可能會導致錯誤。

  • 會話 Cookie——沒有 Max-AgeExpires 屬性的 Cookie——在當前會話結束時刪除。瀏覽器定義“當前會話”何時結束,有些瀏覽器在重新啟動時使用會話恢復。這可能導致會話 Cookie 無限期地持續存在。

    注意:如果您的網站對使用者進行身份驗證,它應該在使用者進行身份驗證時重新生成並重新發送會話 Cookie,即使是已經存在的 Cookie。這種方法有助於防止會話固定攻擊,其中第三方可以重用使用者的會話。

要立即刪除 Cookie,請使用相同的名稱、路徑和域(如果已指定)再次設定 Cookie,並將其 Expires 屬性設定為過去的日期或將其 Max-Age 屬性設定為 0 或負值。這會指示瀏覽器立即刪除 Cookie。例如:

http
Set-Cookie: id=a3fWa; Max-Age=0

您還可以使用Clear-Site-Data 響應頭清除與可註冊域關聯的所有 Cookie。例如,從 https://foo.example.com/ 傳送的以下頭將清除由 example.com 及其所有子域(例如 all.bar.example.com)傳送的所有 Cookie。

http
Clear-Site-Data: "cookies"

有一些技術旨在在 Cookie 被刪除後重新建立它們。這些被稱為“殭屍”Cookie。這些技術違反了使用者隱私和控制的原則,可能違反資料隱私法規,並可能使使用它們的網站面臨法律責任。

要透過 HTTP 更新 Cookie,伺服器可以傳送一個Set-Cookie 標頭,其中包含現有 Cookie 的名稱和新值。例如:

http
Set-Cookie: id=new-value

您可能希望這樣做有幾個原因,例如使用者更新了他們的偏好設定,並且應用程式希望在客戶端資料中反映這些更改(您也可以使用客戶端儲存機制,例如Web Storage)。

透過 JavaScript 更新 Cookie

在瀏覽器中,您可以使用Document.cookie 屬性或非同步Cookie Store API 透過 JavaScript 建立新的 Cookie。請注意,以下所有示例都使用 Document.cookie,因為它是支援最廣泛/最成熟的選項。

js
document.cookie = "yummy_cookie=chocolate";
document.cookie = "tasty_cookie=strawberry";

您還可以訪問現有 Cookie 併為其設定新值:

js
console.log(document.cookie);
// logs "yummy_cookie=chocolate; tasty_cookie=strawberry"

document.cookie = "yummy_cookie=blueberry";

console.log(document.cookie);
// logs "tasty_cookie=strawberry; yummy_cookie=blueberry"

出於安全目的,您無法透過在發起請求時直接傳送更新的 Cookie 標頭來更改 Cookie 值,例如透過fetch()XMLHttpRequest

有一些充分的理由不應該允許 JavaScript 根本修改 Cookie。您可以透過在其建立期間指定HttpOnly 屬性來阻止 JavaScript 訪問 Cookie。有關更多詳細資訊,請參閱安全部分。

安全

當您在 Cookie 中儲存資訊時,預設情況下,所有 Cookie 值對終端使用者都是可見的,並且可以由終端使用者更改。您真的不希望您的 Cookie 被濫用——例如被不良行為者訪問/修改,或傳送到不應該傳送到的域。潛在的後果可能從令人煩惱的(應用程式無法正常工作或表現出奇怪的行為)到災難性的。例如,犯罪分子可以竊取會話 ID 並使用它來設定一個 Cookie,使其看起來像是他們以其他人的身份登入,從而控制他們的銀行或電子商務賬戶。

您可以透過多種方式保護您的 Cookie,本節將對此進行回顧。

阻止訪問您的 Cookie

您可以透過兩種方式確保 Cookie 安全傳送且不會被意外方或指令碼訪問:使用 Secure 屬性和 HttpOnly 屬性:

http
Set-Cookie: id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly
  • 帶有 Secure 屬性的 Cookie 僅透過 HTTPS 協議隨加密請求傳送到伺服器。它絕不會隨不安全的 HTTP 傳送(除了在 localhost 上),這意味著中間人攻擊者無法輕易訪問它。不安全的站點(URL 中帶有 http:)無法設定帶有 Secure 屬性的 Cookie。但是,不要假設 Secure 可以阻止對 Cookie 中敏感資訊的所有訪問。例如,有權訪問客戶端硬碟(或 JavaScript,如果未設定 HttpOnly 屬性)的人可以讀取和修改資訊。

  • 帶有 HttpOnly 屬性的 Cookie 無法被 JavaScript 訪問,例如使用Document.cookie;它只能在到達伺服器時才能訪問。例如,持久化使用者會話的 Cookie 應該設定 HttpOnly 屬性——將它們提供給 JavaScript 會非常不安全。這種預防措施有助於緩解跨站指令碼(XSS)攻擊。

注意:根據應用程式的不同,您可能希望使用伺服器查詢的不透明識別符號,而不是直接將敏感資訊儲存在 Cookie 中,或者研究替代的身份驗證/保密機制,例如JSON Web Tokens

定義 Cookie 的傳送位置

DomainPath 屬性定義了 Cookie 的範圍:Cookie 傳送到哪些 URL。

  • Domain 屬性指定哪個伺服器可以接收 Cookie。如果指定,Cookie 在指定的伺服器及其子域上可用。例如,如果您從 mozilla.org 設定 Domain=mozilla.org,則 Cookie 在該域和 developer.mozilla.org 等子域上可用。

    http
    Set-Cookie: id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly; Domain=mozilla.org
    

    如果 Set-Cookie 標頭未指定 Domain 屬性,則 Cookie 在設定它的伺服器上可用,但不在其子域上可用。因此,指定 Domain 比省略它限制更少。請注意,伺服器只能將其 Domain 屬性設定為其自己的域或父域,而不能設定為子域或其他域。因此,例如,域為 foo.example.com 的伺服器可以將屬性設定為 example.comfoo.example.com,但不能設定為 bar.foo.example.comelsewhere.com(Cookie 仍然會傳送到子域,例如 bar.foo.example.com)。有關更多詳細資訊,請參閱無效域

  • Path 屬性指示請求 URL 中必須存在的 URL 路徑,才能傳送 Cookie 標頭。例如:

    http
    Set-Cookie: id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly; Path=/docs
    

    %x2F ("/") 字元被視為目錄分隔符,子目錄也匹配。例如,如果您設定 Path=/docs,這些請求路徑將匹配:

    • /docs
    • /docs/
    • /docs/Web/
    • /docs/Web/HTTP

    但這些請求路徑不匹配:

    • /
    • /docsets
    • /en-US/docs

    注意:path 屬性允許您根據網站的不同部分控制瀏覽器傳送哪些 Cookie。它不作為安全措施,並且不保護免受從不同路徑對 Cookie 的未經授權的讀取。

使用 SameSite 控制第三方 Cookie

SameSite 屬性允許伺服器指定是否/何時隨跨站點請求傳送 Cookie——即第三方 Cookie。跨站點請求是指站點(可註冊域)和/或方案(http 或 https)與使用者當前訪問的站點不匹配的請求。這包括當點選其他網站上的連結導航到您的網站時傳送的請求,以及嵌入式第三方內容傳送的任何請求。

SameSite 有助於防止資訊洩露,保護使用者隱私,並提供針對跨站點請求偽造攻擊的一些保護。它有三個可能的值:StrictLaxNone

  • Strict 導致瀏覽器僅在響應來自 Cookie 源站點的請求時傳送 Cookie。當您的 Cookie 與始終位於初始導航之後的功能(例如身份驗證或儲存購物車資訊)相關時,應該使用此選項。

    http
    Set-Cookie: cart=110045_77895_53420; SameSite=Strict
    

    注意:用於敏感資訊的 Cookie 也應該具有較短的生命週期

  • Lax 類似,只是瀏覽器在使用者導航到 Cookie 的源站點時也會發送 Cookie(即使使用者來自不同的站點)。這對於影響站點顯示的 Cookie 很有用——例如,您可能在您的網站上有一個包含聯盟連結的合作伙伴產品資訊。當該連結被跟蹤到合作伙伴網站時,他們可能希望設定一個 Cookie,說明已跟蹤了聯盟連結,這將顯示獎勵橫幅並在購買產品時提供折扣。

    http
    Set-Cookie: affiliate=e4rt45dw; SameSite=Lax
    
  • None 指定在源請求和跨站點請求中都發送 Cookie。如果您希望隨嵌入在其他站點中的第三方內容(例如廣告技術或分析提供商)發出的請求傳送 Cookie,這很有用。請注意,如果設定了 SameSite=None,則還必須設定 Secure 屬性——SameSite=None 需要安全上下文

    http
    Set-Cookie: widget_session=7yjgj57e4n3d; SameSite=None; Secure; HttpOnly
    

如果沒有設定 SameSite 屬性,則預設將 Cookie 視為 Lax

由於 Cookie 機制的設計,伺服器無法確認 Cookie 是否從安全來源設定,甚至無法判斷 Cookie 最初在何處設定。

子域上的應用程式可以設定具有 Domain 屬性的 Cookie,這使得可以在所有其他子域上訪問該 Cookie。這種機制可能在會話固定攻擊中被濫用。

作為縱深防禦措施,您可以使用Cookie 字首對支援的使用者代理中的 Cookie 屬性施加特定限制。所有 Cookie 字首都以雙下劃線(__)開頭並以破折號(-)結尾。有四個字首可用:

  • __Secure-:名稱以 __Secure- 開頭的 cookie 必須由安全頁面 (HTTPS) 設定 Secure 屬性。
  • __Host-:名稱以 __Host- 開頭的 cookie 必須由安全頁面 (HTTPS) 設定 Secure 屬性。此外,它們不能指定 Domain 屬性,並且 Path 屬性必須設定為 /。這保證了此類 cookie 僅傳送給設定它們的主機,而不傳送給域上的任何其他主機。它還保證它們在主機範圍內設定,並且不能被該主機上的任何路徑覆蓋。這種組合產生了一個儘可能接近將來源視為安全邊界的 cookie。
  • __Http-:名稱以 __Http- 開頭的 Cookie 必須由安全頁面 (HTTPS) 設定 Secure 標誌,並且還必須設定 HttpOnly 屬性以證明它們是透過 Set-Cookie 標頭設定的(它們不能透過 JavaScript 功能(例如Document.cookieCookie Store API)設定或修改)。
  • __Host-Http-:名稱以 __Host-Http- 開頭的 cookie 必須由安全頁面 (HTTPS) 設定 Secure 標誌,並且必須設定 HttpOnly 屬性以證明它們是透過 Set-Cookie 頭設定的。此外,它們還具有與 __Host- 字首 cookie 相同的限制。這種組合產生了一個儘可能接近將來源視為安全邊界的 cookie,同時確保開發人員和伺服器操作員知道其範圍僅限於 HTTP 請求。

瀏覽器將拒絕不符合其限制的帶有這些字首的 Cookie。由於應用程式伺服器在確定使用者是否已透過身份驗證或 CSRF 令牌是否正確時僅檢查特定的 Cookie 名稱,因此這實際上是針對會話固定的防禦措施。

注意:在伺服器上,Web 應用程式必須檢查包括字首在內的完整 Cookie 名稱。使用者代理在請求的Cookie 標頭中傳送 Cookie 之前不會去除字首。

有關 Cookie 字首和瀏覽器支援當前狀態的更多資訊,請參閱Set-Cookie 參考文章的字首部分

隱私與追蹤

早些時候我們討論了 SameSite 屬性如何用於控制何時傳送第三方 Cookie,以及這如何有助於保護使用者隱私。隱私是構建網站時非常重要的考慮因素,如果做得好,可以與您的使用者建立信任。如果做得不好,它可能會完全侵蝕這種信任並導致各種其他問題。

第三方 Cookie 可以由透過<iframe> 嵌入在網站中的第三方內容設定。它們有許多合法用途,包括共享使用者配置檔案資訊、計算廣告展示次數或跨不同相關域收集分析資料。

然而,第三方 Cookie 也可能被用來建立令人毛骨悚然、侵入性的使用者體驗。第三方伺服器可以根據同一瀏覽器在訪問多個網站時傳送給它的 Cookie 來建立使用者瀏覽歷史和習慣的配置檔案。典型的例子是,當您在一個網站上搜索產品資訊時,無論您走到哪裡,都會被類似產品的廣告追逐。

瀏覽器供應商知道使用者不喜歡這種行為,因此都已開始預設阻止第三方 Cookie,或者至少計劃朝這個方向發展。第三方 Cookie(或僅跟蹤 Cookie)也可能被其他瀏覽器設定或擴充套件程式阻止。

注意:Cookie 阻止可能導致某些第三方元件(例如社交媒體小部件)無法按預期執行。隨著瀏覽器對第三方 Cookie 施加更多限制,開發人員應該開始尋找減少對它們依賴的方法。

有關第三方 Cookie、與之相關的問題以及可用替代方案的詳細資訊,請參閱我們的第三方 Cookie 文章。有關隱私的更多資訊,請參閱我們的隱私著陸頁。

涵蓋 Cookie 使用的法律法規包括:

這些法規具有全球影響力。它們適用於來自這些司法管轄區(歐盟和加利福尼亞州,但加利福尼亞州的法律僅適用於總收入超過 2500 萬美元的實體等)的使用者訪問的任何萬維網站。

這些法規包括以下要求:

  • 通知使用者您的網站使用 Cookie。
  • 允許使用者選擇退出接收部分或全部 Cookie。
  • 允許使用者在不接收 Cookie 的情況下使用您的大部分服務。

您所在地區可能還有其他管理 Cookie 使用的法規。您有責任瞭解並遵守這些法規。有些公司提供“Cookie 橫幅”程式碼,可幫助您遵守這些法規。

注意:公司應披露其網站上使用的 Cookie 型別,以實現透明度並遵守法規。例如,請參閱Google 關於其使用的 Cookie 型別的通知,以及 Mozilla 的網站、通訊和 Cookie 隱私通知

另見