此筆記參考網路文章與資源,內文描述有雷同請見諒,僅作為筆記之用。
Web 開發者一定要了解 HTTP 無狀態的特性,要在網路上保存狀態、識別使用者,必須透過適當的機制去完成(常見的就是 Cookie),繼滿久之前寫的一篇關於 Session 的介紹,這次主要是想筆記一些 Cookie 設置的特性。
< Cookie Basic >:
- 一個 Cookie 最多可以存成 4KB (4093 bytes) 的大小。
- 一個 Domain 最好不要超過 50 個 Cookies, 如此可以符合絕大部分的 User Agent,再更好的話最好不要超過 20 個,因為有些 IE 版本只支援 20 個,雖然現在 IE 已漸漸淡出。
- 大部分 User Agent 至少可設置 20 個 Cookies (也就是說針對同一個 Domain 至少可以存 20 個 Cookies)。
- 前面1、2、3點,關於 Cookie 大小以及設置的容量極限,根據不同 User Agent 會有不同差異。
- Cookies 在資安方面要注意、而在效能方面也要考慮,過多也不是好事。
< 建立 Cookie >:
一. 首先設定 Cookie 的流程大概像這樣。
- Server 收到一個 HTTP Request。
- Server 回傳 Response 時在 Header 送一個
Set-Cookie
的設定。
|
|
- User Agent 收到後,把 Cookie 以
key-value
的形式存在自己手裡。 - 下一次 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 在幾秒後過期- 如果
Expires
和Max-Age
同時出現,那Max-Age
優先度更高。 - 設定為
0
或負數
,此 Set-Cookie 在送到 User Agent 儲存時會直接失效。
- 如果
-
Domain(Optional)
Domain=<domain-value>
: 設置這個 Cookie 可以被送去哪個 Domain,也就是說這個 Cookie 在哪些 Domain 下出現是合理的。- 基本運作邏輯:
-
- Client端,如果網站的域名為
a.site.com
,那在 Client 的合理 Domain 只能是a.site.com
或是父域名site.com
,同級的域名像是b.site.com
是無效的。
- Client端,如果網站的域名為
-
- Server端,如果網站的域名為
server.site.com
,那在 Server 的合理 Domain 只能是server.site.com
或是父域名site.com
,同級域名像是server2.sit‘e.com
是無效的。
- Server端,如果網站的域名為
-
- 所以根據第 1、2 點,如果今天 Client 的 Domain 是
a.site.com
,Server 是server.site.com
這時候 Domain 只能設置site.com
才可以在兩方正確運作。
- 所以根據第 1、2 點,如果今天 Client 的 Domain 是
-
- 設置規則: 根據運作邏輯,設置 Cookie 有一些規則
-
- Cookie 的 Origin Domain 為 Client 發出 Request 時的 Domain。(假設為
site.com
)
- Cookie 的 Origin Domain 為 Client 發出 Request 時的 Domain。(假設為
-
- 如果 Domain 沒有設置,那預設 Cookie 只能在 Origin Domain 運作,其他都不行,包括子域名。(此時 Domain 的域名就會是
site.com
)
- 如果 Domain 沒有設置,那預設 Cookie 只能在 Origin Domain 運作,其他都不行,包括子域名。(此時 Domain 的域名就會是
-
- 如果 Domain 有設置,那 Cookie 能夠在此設置的 Domain 和他的所有子域名運作。(以 chromium based 的 User Agent 來說假設設置為
site.com
,此時 Domain 的域名就會是.site.com
, 會在前面多一個.
,這個.
表示允許此 Domain 以及他的所有 Sub Domain.)
- 如果 Domain 有設置,那 Cookie 能夠在此設置的 Domain 和他的所有子域名運作。(以 chromium based 的 User Agent 來說假設設置為
-
- 如果 Origin Domain 是 IP,這時不能夠設置 Domain,但相對的也會符合第 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- 這個 HttpOnly 很重要,可以防止 XSS(Cross-site scripting)。
- 像是
Document.cookie
就會拿不到 Cookie。
-
SameSite(Optional):
SameSite=<samesite-value>
: 控制 Cookie 可不可以被跨站請求傳送,- 可以防止 CSRF跨站請求偽照(Cross Site Request Forgery)
- 有三種設定分別是
Strict
、Lax
、None
- 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.com
和b.site.com
屬於同一個 site,但像github.io
在 Public Suffix List 中,那a.github.io
和b.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 >:
-
Set-Cookie 的 Detail 可以參考 MDN/Set-Cookie
-
Cookie 的 SameSite 可以參考 iT幫幫忙
-
什麼是 CSRF:
-
什麼是 XSS:
-
什麼是 CSP: