跨站請求偽造
跨站請求偽造(又被稱為 CSRF 或者 XSRF ),它源自一個域網站向另一個域網站發起請求的簡單功能。攻擊者通過一些技術手段欺騙用戶使用瀏覽器去訪問一個自己曾經認證過的網站并執行一些敏感操作(如轉賬)。
一個域網站向另一個域的網站發起請求的方式有很多,例如點擊一個超鏈接、加載靜態資源、提交表單以及直接發起 ajax 請求等。如:
<a >點擊有驚喜</a> # 誘導用戶點擊
<img src="http://a.com/xx" > # 瀏覽器默認加載資源 - 圖片
<link rel="stylesheet" > # 瀏覽器默認加載資源 - css 文件
<form method="post" action="http://a.com/xx"> # 構造可以提交的表單
<input type="text" name="name" value="value">
<input type="submit" >
</form>
如果用戶之前在 a.com 認證過,即瀏覽器保持有效的 cookie ,這些請求也會攜帶相應的 cookie ,而用戶可能并不知情。
Same-Site Cookies
Same-Site Cookies 出現以前我們并沒有一種簡單而有效的方式去阻止 CSRF 攻擊,其中一種方式是通過檢查 origin 和 referer 來校驗,缺點是依賴瀏覽器發送正確的字段,而這并不總是準確有效的;另一種方式則是通過給表單添加隨機 token 的方式來校驗,但是部署比較麻煩。
Same-Site Cookies 的出現就是為了解決這個問題,它可以完全有效的阻止 CSRF 攻擊。Same-Site Cookies 非常容易部署,只需要將你原來的設置 cookie 的地方,如下:
Set-Cookie: key=value; path=/
改為:
Set-Cookie: key=value; path=/; SameSite
準確的說 SameSite 這個屬性有兩個可選值,分別是 Strict 和 Lax 。其中 Strict 為嚴格模式,另一個域發起的任何請求都不會攜帶該類型的 cookie,能夠完美的阻止 CSRF 攻擊,但是也可能帶來了少許不便之處,例如通過一個導航網站的超鏈接打開另一個域的網頁會因為沒有攜帶 cookie 而導致沒有登錄等問題。因此 Lax 相對于 Strict 模式來說,放寬了一些。簡單來說就是,用 「安全」的 HTTP 方法(GET、HEAD、OPTIONS 和 TRACE)改變了當前頁面或者打開了新頁面時,可以攜帶該類型的 cookie。具體見下表:
請求類型 | 例子 | 非 SameSite | SameSite = Lax | SameSite = Strict |
---|---|---|---|---|
link | <a href="…"> |
Y | Y | N |
prerender | <link rel="prerender" href="…"> |
Y | Y | N |
form get | <form method="get" action="…"> |
Y | Y | N |
form post | <form method="post" action="…"> |
Y | N | N |
iframe | <iframe src="…"> |
Y | N | N |
ajax | $.get('…') |
Y | N | N |
image | <img src="…"> |
Y | N | N |
演示
傳統 Cookie
現在 a.com 域下設置傳統的 cookie,如下:
現在 b.com 的網頁加載 a.com 的 css 文件時會攜帶該 cookie,如下:
b.com 的網頁中的表單向 a.com 中的接口提交數據時也會攜帶該 cookie,如下:
SameSite = Strict
現在將該 cookie 改為 SameSite = Strict,如下:
現在 b.com 的網頁加載 a.com 的 css 文件時不會再攜帶該 cookie,如下:
b.com 的網頁中的表單向 a.com 中的接口提交數據時也不會再攜帶該 cookie,如下:
b.com 的網頁中通過點擊超鏈接打開的 a.com 的網頁也不會攜帶該 cookie,如下:
SameSite = Lax
現在將該 cookie 改為 SameSite = Strict,如下:
SameSite = Lax 時表現與 SameSite = Strict 時完全一致,除了通過點擊超鏈接打開的 a.com 的網頁時會攜帶該 cookie,如下: