Contents

SameSite Cookie 和 Same Origin Policy 是什麼

一般我們使用 Ajax 很長遇到跨域問題,之前我們很長設定 CORS 後端坐跨域設定結束這一回合。最近有研究 SSO 登入,有關 cookies 在不同子網域能不能做到 cookies 問題,原本覺得 cookies 是走 origin 的。結果後來發現 cookies 是走 SameSite ,我這邊就馬上惡補一下。結果發現有些東西很重要,但我竟然不知道,這邊簡單筆記一下。不過大致上你沒有要做到跨子網域登入一些東西可能就用不太到。

推薦文章

以上筆記從上面內容自己參考,真的上面內容都很完整,這邊簡單紀錄重點讓我方便回來複習。

小記

單字名詞意思

https://tw.yahoo.com:443

scheme

scheme 中文翻譯叫 方案 。可參考scheme - Yahoo奇摩字典 搜尋結果

簡單就是https://tw.yahoo.com:443裡面的https

常見的 https,http,ftp都是。

port

中文叫通訊協定,不過通常翻譯叫馬頭(港口)。

簡單就是https://tw.yahoo.com:443裡面的443

host

中間那一串就是tw.yahoo.com

Warning
下面 SameSite 和 Same Origin 是不一樣的,SameSite這邊比對 host 是指registrable domain。Same Origin 是指完整子網域。這邊在比對上一開始也是看不懂,下面有提到eTLD,相關去看如何判斷兩個網域的擁有者是否相同? | 半熟前端了解規則就容易了解差異。

Info
這邊原本 SameSite 標題,因為我看 SameSite 通常用在 Cookie 上面,MDN標題也叫 SameSite Cookie參考這篇,但我下面還是用 SameSite 來說

SameSite 很多網站都說scheme + host。不看 port。
這邊很多網站沒有細提 host 這邊指的是 registrable domain
其實這邊在我沒有仔細了解之前,我以為 domain 會抓憑證資訊或者是 xxxx.com.tw之類的
沒有想到是跟 eTLD有關係。可以看 如何判斷兩個網域的擁有者是否相同? | 半熟前端 備份圖

網域的運作機制對於前端最大的意義在於 SameSite2 的判斷,我們想要知道兩個網站是否為 SameSite,因為在 SameSite 的情況下網站的 Cookie 是共享的(在沒有特別設定 header 的情況下)。

因此給定兩個網站 URL,kalan.hacker.com 跟 jack.hacker.com,請問這兩個 URL 是否為 SameSite?乍看之下兩個 URL 很像 hacker.com 的 subdomain,但看完剛剛的例子與說明,我們應該先看看 hacker.com 有沒有在 public suffix list 裡才能做判斷。
在 GitHub 當中,可以透過 Repository 的設定免費生成 xxx.github.io 的網域 ,像是我的舊部落格: kjj6198.github.io/blog 。在這種情況下,我們可不希望每個 xxx.github.io 的 cookie 都可以互相存取。對於這類型的應用來說,我們希望的是每個 xxx.github.io 都是一個獨立的網域,而不是 .github.io 的子網域,透過 eTLD 可以有效解決這個問題,查看 public suffix list 也確實可以找到 .github.io 的存在

其實看到這邊就還蠻驚訝的!!我用電腦這麼久都不知道有這麼有趣機制XD
這邊其實不是重點,我就不繼續興奮討論。

這邊看SameSite小識 - 知乎實戰

我們假設有一個名字為sessionId的cookie,domain 設置成了 .demo.com。

  1. 在 a.demo.com 域名下,ajax在該域名下的所有請求,都會自動帶上sessionId。
    ajax.get(’/api/data’) // 自動帶上sessionId
  2. 在b.demo.com域名下,ajax在該域名下的所有請求,都會自動帶上sessionId。
    ajax.post(’/api2/data2’) // 自動帶上sessionId
  3. 在b.demo.com域名下,ajax請求a.demo.com的api,需要設置withCredentials才能帶上sessionId

ajax.get(‘https://a.demo.com/api/data') // 不能自動帶上sessionId

ajax.get(‘https://a.demo.com/api/data', {withCredentials: true}) // 自動帶上sessionId

這邊我們可以看到在 request 訪問 a.demo.comb.demo.com 都會傳送 主網域.demo.com cookies 資料。

瀏覽器 Demo

我直接用 Yahoo 新聞來看。開發者工具可以看到網站有用那些 cookies下圖。

https://i.imgur.com/yR0QdSy.png

在訪問https://tw.news.yahoo.com 會帶相關 cookies

https://i.imgur.com/ipOrZP3.png

但是在訪問非 https://tw.news.yahoo.com 網域 thamba因 domain 設定在 https://tw.news.yahoo.com,不會送出這組 cookies。參考下圖,我使用隨便不同子網域,並不回帶入thamba cookies。下面改成用Firefox,因為Chrome 404不會顯示傳什麼 cookies。

https://i.imgur.com/49t7Dzj.png

注意整體 cookies 並非一致設定,可以個別設定。
上面不是有提到 registrable domain 是使用 eTLD 關係查到。
Firefox 和 Edge 可以看出 registrable domain
https://i.imgur.com/CiPK4lO.png

我們寫 cookies 進去通常有一個 domain 欄位,通常都不會帶。但瀏覽器不會隨便給你亂設定網域,這邊他會寫eTLD,除非你有寫正確子網域。我以前都不知道為什麼沒法修改 domain ,現在知道為什麼了。

https://i.imgur.com/9ItTZmL.png

可能忽略 Cookies 跨域設定

參考: SameSite小識 - 知乎
https://i.imgur.com/DCtW7eW.png

我們常常前端串後端,因後端不同網域通常會後端加

1
2
3
4
5
6
router.get('/api/data', (ctx, next) => {
  ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);
  ctx.set('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , myheader');
  ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
  ctx.set('Access-Control-Allow-Credentials', 'true');
};

但我們很少探討前端要怎麼跨域傳 cookies ,這邊還是傳送 SameSite喔

1
2
3
ajax.get('https://a.demo.com/api/data') // 不能自動帶上sessionId

ajax.get('https://a.demo.com/api/data', {withCredentials: true}) // 自動帶上sessionId

SameSite 規則設定

SameSite可以有下面三種值:

Strict僅允許一方請求攜帶Cookie,即瀏覽器將只發送相同站點請求的Cookie,即當前網頁URL與請求目標URL完全一致。
Lax允許部分第三方請求攜帶Cookie
None無論是否跨站都會發送Cookie

通常程式沒指定,預設都是Lax

https://i.imgur.com/ypsKPZL.png

Strict
只在 First-party 環境下帶上 Cookie,但這有個問題,假設使用者在 example.com 看到一條 FB 貼文連結(假設為 fb.com),就算使用者曾經登入過 fb.com 取得了 Cookie,點擊連結後因為兩個網站為 Cross-site,不會帶上 Cookie,只能看到登入頁面。

因此 Strict 適合用在操作,例如刪除貼文、付款等等。
參考:[Day 26] Cookies - SameSite Attribute - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天

這邊簡單想就是從外站(包含子網域)連到主網站 cookies 會不會帶入問題,這邊我還沒實驗。但看到上面探討 CORS 安全性問題大概應該是這樣,目前還沒想到簡易實作。這邊我有簡單做個實作測試,可以參考簡單實作測試 SameSite 的規則(Lax,Strict,None) - 程式狂想筆記

跨域傳 cookies 需要 https

SameSite=Strict:最嚴謹,只有與目前網頁網址一致才能發送 (remote.example、site.example 互相無法發送)
Set-Cookie: CookieName=CookieValue; SameSite=Strict;
SameSite=Lax:使用 GET remote.example 向 site.example 發送,Cookie 將會送向 remote.example (POST 則不會發送 Cookie)
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
SameSite=None + HTTPS:允許跨網域存取,但是若沒 HTTPS 則預設「拒絕」跨網域存取
無效:Set-Cookie: remote_session=abc123; SameSite=None
有效:Set-Cookie: remote_session=abc123; SameSite=None; Secure

參考:PHP Cookie SameSite 的設定方式 – Tsung’s Blog

我要測試 http 想說怎麼Lax塞不進去,發現要 https

Same Origin Policy

建議可以看 簡單弄懂同源政策 (Same Origin Policy) 與跨網域 (CORS) | by Hannah Lin | Starbugs Weekly 星巴哥技術專欄 | Medium,因為這個我以前就很常遇到,所以就不仔細記錄。

檢查

  1. scheme
  2. host (跟samesite 不一樣的是不看registrable domain,是整個子網域)
  3. port

比 SameSite 非常嚴格。

這邊簡單看 MDN給的判斷範例就一目瞭然。
https://i.imgur.com/zDC9BPm.png

這邊還是不知道差異嗎?這邊有比較可以參考

https://user-images.githubusercontent.com/6058558/219940755-bb808816-7cad-44dc-8c65-67c34e50a334.png

參考:忍術!把 same site 變 same origin 之術! - Huli’s blog