關於 Session 與 Cookie - [ Cookie篇 ] 紀錄

Cookie 好吃?

此筆記參考網路文章與資源,內文描述有雷同請見諒,僅作為筆記之用。


Web 開發者一定要了解 HTTP 無狀態的特性,要在網路上保存狀態、識別使用者,必須透過適當的機制去完成(常見的就是 Cookie),繼滿久之前寫的一篇關於 Session 的介紹,這次主要是想筆記一些 Cookie 設置的特性。

  1. 一個 Cookie 最多可以存成 4KB (4093 bytes) 的大小。
  2. 一個 Domain 最好不要超過 50 個 Cookies, 如此可以符合絕大部分的 User Agent,再更好的話最好不要超過 20 個,因為有些 IE 版本只支援 20 個,雖然現在 IE 已漸漸淡出。
  3. 大部分 User Agent 至少可設置 20 個 Cookies (也就是說針對同一個 Domain 至少可以存 20 個 Cookies)。
  4. 前面1、2、3點,關於 Cookie 大小以及設置的容量極限,根據不同 User Agent 會有不同差異。
  5. Cookies 在資安方面要注意、而在效能方面也要考慮,過多也不是好事。

一. 首先設定 Cookie 的流程大概像這樣。

  1. Server 收到一個 HTTP Request。
  2. Server 回傳 Response 時在 Header 送一個 Set-Cookie 的設定。
1
2
# 像這樣
Set-Cookie: <cookie-name>=<cookie-value>
  1. User Agent 收到後,把 Cookie 以 key-value 的形式存在自己手裡。
  2. 下一次 User Agent 發出 HTTP Request 時,Header 會自動帶此 Cookie。

二. 一般來說,每個 Cookie 以 key-value 的形式儲存之外,還會有底下這些屬性能夠去設定當前這個 Cookie 的特性:

  • Expires(Optional) Expires=<date>: 設置這個 Cookie 的具體有效日期

    • 如果沒有設置,預設就會是 Session Cookie (會話 Cookie),這個 Session Cookie 存在 Client 的暫存記憶體,當 Client 不再運作(像是關閉 Browser)這個 Session Cookie 就會消失,但其實很多 Browser 都有回覆 Session 狀態的功能,所以假設不是嚴格意義上的完全停止 Client 的運作(ex: 退出 Chrome App),就連 Session Cookie 也都有機會回覆。
    • 有沒有過期,是在 Client 端的日期判斷為主, 而不是 Server。
  • Max-Age(Optional) Max-Age=<number>: 設置這個 Cookie 在幾秒後過期

    • 如果 ExpiresMax-Age 同時出現,那 Max-Age 優先度更高。
    • 設定為 0負數,此 Set-Cookie 在送到 User Agent 儲存時會直接失效。
  • Domain(Optional) Domain=<domain-value>: 設置這個 Cookie 可以被送去哪個 Domain,也就是說這個 Cookie 在哪些 Domain 下出現是合理的。

    • 基本運作邏輯:
        1. Client端,如果網站的域名為 a.site.com,那在 Client 的合理 Domain 只能是 a.site.com 或是父域名 site.com ,同級的域名像是 b.site.com 是無效的。
        1. Server端,如果網站的域名為 server.site.com,那在 Server 的合理 Domain 只能是 server.site.com 或是父域名 site.com,同級域名像是 server2.sit‘e.com 是無效的。
        1. 所以根據第 1、2 點,如果今天 Client 的 Domain 是 a.site.com,Server 是 server.site.com 這時候 Domain 只能設置 site.com 才可以在兩方正確運作。
    • 設置規則: 根據運作邏輯,設置 Cookie 有一些規則
        1. Cookie 的 Origin Domain 為 Client 發出 Request 時的 Domain。(假設為site.com)
        1. 如果 Domain 沒有設置,那預設 Cookie 只能在 Origin Domain 運作,其他都不行,包括子域名。(此時 Domain 的域名就會是 site.com)
        1. 如果 Domain 有設置,那 Cookie 能夠在此設置的 Domain 和他的所有子域名運作。(以 chromium based 的 User Agent 來說假設設置為 site.com,此時 Domain 的域名就會是 .site.com, 會在前面多一個 . ,這個 . 表示允許此 Domain 以及他的所有 Sub Domain.)
        1. 如果 Origin Domain 是 IP,這時不能夠設置 Domain,但相對的也會符合第 1 點的運作。
        1. 所以根據運作邏輯,想要運作則是當在 site.com 時,Cookie 不能設置為 a.site.com,但在 a.site.com 時可以設置 site.com,但也不能設置 b.site.com 和 其他 Domain。
  • Path(Optional) Path=<path-value>: 設置可以共享這個 Cookie 的 Path。

    • 不設置的話,預設為 / ,底下的 Path 都可以共享這個 Cookie。
  • Secure(Optional) Secure : 只能透過 Secure 的管道被傳輸(SSL),而依據目前主流的實作,要透過 HTTPS 來傳送,不能是 HTTP。

    • 這個 Secure 很重要,可以防止基本的 MITM中間人攻擊(Man-in-the-middle attack)
    • 所以當 Server 是 HTTP 且 Set-Header 有設置 Secure 但還傳送時,事實上 Set-Cookie 裡的資料還是有的,只是被 User Agent 拒絕了。
  • HttpOnly(Optional): httpOnly=true / httpOnly : 禁止使用 JS 獲取 cookie

  • SameSite(Optional): SameSite=<samesite-value>: 控制 Cookie 可不可以被跨站請求傳送,

    • 可以防止 CSRF跨站請求偽照(Cross Site Request Forgery)
    • 有三種設定分別是 StrictLaxNone
      • Strict: same-site 才可以送 Cookie。
      • Lax(default值):same-site 才可以送,但在某些時刻可以,如下:
      <a href="..."></a>
      <link rel="prerender" href="..."/>
      <form method="GET" action="..."> 但是 POST 方法 的 form,或是只要是 POST, PUT, DELETE 這些方法,就不會帶上 cookie
      
      • None: same-site, cross-site 都送,且要加上 Secure 屬性像這樣: SameSite=None; Secure;
    • 要把 Site 和 Origin 分清:
      • Origin: Scheme(ex: https)、Host(ex: www.site.com)、Port(ex: 80),真正的 Same-Origin 是 3 個都一樣才是, 其餘都是 Cross-Origin。(但這裡要注意,Cookie 在確認是不是同個 origin 時,是只看 host 以及 Path 的設定、還有 Secure 的設定來確認 Cookie 能不能夠存在)
      • Site: Same-Site 的判定關係到 Effetive top-level domains(eTLDs),eTLDs 被定義在 Public Suffix List 中,而 Site 是由 eTLD 加上一個前綴組成。假設 site.com 不在 Public Suffix List 中,但是 .com 存在,意思是說,那 site.com 是一個 site 沒錯,同時 a.site.comb.site.com 屬於同一個 site,但像 github.io 在 Public Suffix List 中,那 a.github.iob.github.io 就不是同一個 site。

何謂 Public Suffix List: 參考

先知道 TLD 再理解 eTLD, eTLD 都放在 Public Suffix List 裡 
比如說 `.com` 在 Public Suffix List 裡面。
那為什麼 `.com` 在裡面,因為 `.com` 太多人用了,我必須限制 `site.com` 不會干涉到世界其他 `.com` 結尾的網站,有點這樣的感覺。
那 `site.com` 就是一個 site,`site2.com` 就是另一個 Site。
而 `a.site.com` 和 `b.site.com` 就是 Same-Site。

那為什麼 `github.io` 在裡面,因為 `github.io` 在世界上也太多人擁有了,為了不互相干涉,以及干涉到 `github.io`。
那這時 `a.github.io` 和 `b.github.io` 就是 Cross-Site。

所以把他們歸納起來,如此就可以知道 Domain 與 Domain 之間 Same-Site 和 Cross-Site 關係。

< Persistent & Session (Transient) >:

沒有設置 Expires 就是 Session Cookie 存在 Memory,隨著 User Agent 關閉而消失。
其餘的是 Persistent Cookie,存在 User Agent,也就是 User 的 Disk 裡。

< References >: