昨天講了 Secure 跟 HttpOnly 之後,今天要講的 SameSite 是一個比較複雜的 cookie 屬性,需要花比較多時間講,所以我們二話不說馬上開始吧!
在講 SameSite 之前,這邊要先來談談什麼是 CSRF 攻擊:
事情是這樣的,假設你有一個豬豬銀行的網路銀行帳號,只要你用瀏覽器上他們網站登入後,就可以進行轉帳、買賣外幣等等操作。而這個豬豬銀行的網站也會在你登入時放一個識別用的 session cookie 到你的瀏覽器裡面,假設那個 cookie 長這樣:Set-Cookie: id=123aaa; Domain=pigbank.com; Secure
因為豬豬銀行設定這個 cookie 不會馬上過期,如果當你的瀏覽器中有這個 cookie 時,你不小心去到一個很壞很壞的網站 badguy.com,這個網站裡面剛好有一個表單長這樣
<form action="https://pigbank.com/transfer" method="POST">
<input type="hidden" name="acct" value="badguy"/> <!-- 隱藏欄位 -->
<input type="hidden" name="amount" value="10000"/> <!-- 隱藏欄位 -->
<input type="submit" value="免費註冊"/> <!-- 註冊按鈕 -->
</form>
那在你按下「免費註冊」的按鈕時,網頁就會發送一個請求給 https://pigbank.com/transfer
要求轉帳,而且因為你剛剛曾經登入過豬豬銀行,因此這個請求會帶著 Cookie: id=123aaa; Domain=pigbank.com
一起出去,以你的名義進行轉帳。而豬豬銀行的 API Server 看到這個請求後,因為 cookie 看起來也沒什麼問題,所以他就會以為是你本人登入在操作,於是就真的把你的一萬塊轉給 bad guy 了
以上就是 CSRF 攻擊的原理,簡單來說他就是利用瀏覽器會自動帶上 cookie 的機制,趁你的 cookie 還在時偷偷發出偽造請求。而 API Server 那邊因為看到 cookie 就以為是本人,所以就被偽造請求騙過去
從上面的案例可以看出來,CSRF 的根本問題在於瀏覽器發送請求時會自動帶上 cookie,所以 SameSite 屬性為了解決 CSRF,就是要將自動送出 cookie 的條件變得更嚴苛
因為 SameSite 總共有 Strict、Lax、None 三個值可以設定,這邊就從最嚴格的 Strict 開始講起
所謂的 SameSite=Strict
就是指這個 cookie 只有在自己的網站上才會被發送出去,因此如果豬豬銀行設定的是 Set-Cookie: id=123aaa; SameSite=Strict; Secure
,那就只有當使用者在操作豬豬銀行網站時,這個 cookie 才會被帶上。若是你在別人的網站上點到惡意的按鈕,不小心發了 POST 請求到 https://pigbank.com/transfer
,那就不會帶上 cookie
因為設定了 SameSite=Strict
之後可以防止 cookie 在其他網站上被發送出去,也就完全避免了 CSRF 攻擊
雖然使用 SameSite=Strict
可以達到最高的安全性,但完全禁止 cookie 在其他網站上被發送出去有點太嚴格了,有些服務(譬如說 Facebook 登入)為了知道使用者的狀態,他一定得在你寫的網站上把他自己的 cookie 送出去,因此他們就不會幫自家的 cookie 設定 SameSite=Strict
,取而代之的是 SameSite=Lax
相較於 Strict 的完全禁止,Lax 允許你在頁面跳轉到其他網域時順便把該網域的 cookie 送出去,聽起來有點抽象對吧?譬如說我們在按下「Sign in with Facebook」時,如果 Facebook 的 cookie 是設定 SameSite=Strict
,那 cookie 就不會送出去,也就無法成功使用 Facebook 登入。但因為按下「Sign in with Facebook」時會開啟一個新視窗跳轉到 Facebook 的網域,所以如果你是設定 SameSite=Lax
,Facebook 的 cookie 就會一併被送出去,也就可以成功使用 Facebook 登入~
另外值得一提的是,因為設定成 Lax 可以兼顧方便性跟安全性,所以這兩年來很多瀏覽器如 Chrome、Firefox 都把 SameSite 預設值設為 Lax,即便很多網站沒有特別指定 Cookie 的 SameSite 屬性,瀏覽器也可以藉此幫他們提升安全性
最後就是 SameSite=None
,所謂的 None 就是沒有XD,所以我們上面講的那些防護功能他通通都沒有,對 CSRF 的防護力當然也是零
雖然還是有少數情況真的會需要用到 None 來突破 Lax 的限制,但除非你做的是像 GA 這種三不五時就要從別人的網站把 cookie 送回 Google 的服務,否則絕大多數時候你都不會需要 None,就放心的用 Lax 就好了
今天介紹了鼎鼎大名的 CSRF 攻擊,以及用來對付他的 SameSite 屬性,今天的內容比較複雜一點,如果有哪邊不是很理解的歡迎在下方留言問我,我都會盡力回答大家的。如果沒問題的話,那明天就要來講講要怎麼在 API Server 設定 cookie 的屬性,算是相對比較輕鬆的內容~