網站一般會使用 cookie 來記錄用戶的登陸狀態,但並不是安全,由於 cookie 被容許在第三方網站(也不只限於第三方)發起的請求中攜帶,所以利用這一點能夠達到 CSRF 攻擊。本文再也不對 CSRF 的原理做過多闡述,點擊這裏瞭解CSRF 。
若是別人問起防 CSRF 的方法有哪些,你們一般會說出:Token + Referer,該方案在業界已經很是成熟。當一個問題有了解決辦法後,就很人有人會去了解別的方案,我想聽聽不一樣的聲音。html
有位社會人曾經說過:有趣的靈魂萬里挑一。
本文給你們介紹另外一種防 CSRF 的方法。json
開始前咱們先了解一下第三方請求,什麼樣的請求被稱爲第三方請求?簡單來講就是在一個網頁上發起一個不一樣源的請求,那麼咱們能夠稱爲第三方請求。 安全
在一個頁面上發起一個第三方請求能夠分爲有 異步請求 和 同步請求:
一、異步請求 指的是在當前頁面上經過 script
、 link
、img
、fetch
、XHR
等方法發起的請求,這些都不會讓頁面發生變化,也不會打開新的頁面。
二、同步請求 指的是在當前頁面點擊 <a>
標籤,或 <form>
提交、 JS 調起的 location.href
、window.open()
等方式發起的請求,這些方式可能會使當前頁面刷新或者打開新的頁面。cookie
經過 a.com 的頁面發起 a.com 的請求,會帶上第一方 cookie (first-party cookie)。
經過 a.com 的頁面發起 b.com 或 c.com 的請求,會自動帶上第三方 cookie (third-party cookie)
CSRF 就是利用第三方請求會帶上第三方 cookie 的弱點來達到在一個不信任的域下也能夠達到的危險操做。dom
正如文章開頭所說的防 CSRF 能夠直接上方案 Token + Referer,可是人家 Google 就是要改變世界,怎麼說? Google 提了一份草案 ,給 cookie 新增 SameSite 屬性,經過這個屬性能夠標記哪一個 cookie 只做爲同站 cookie (即第一方 cookie,不能做爲第三方 cookie),既然不能做爲第三方 cookie ,那麼別的網站發起第三方請求時,第三方網站是收不到這個被標記關鍵 cookie,後面的鑑權處理就好辦了。這一切都不須要作 token 生命週期的管理,也不用擔憂 Referer 會丟失或被中途被篡改。異步
SameStie 有兩個值:Strict 和 Lax:工具
嚴格模式,使用 SameSite=Strict
去標記的 cookie 在任何狀況下(包括異步請求和同步請求) 都不能做爲第三方 cookie。fetch
寬鬆模式,使用 SameSite=Lax
去標記的 cookie 在異步請求 和 form 提交跳轉的狀況下 都不能做爲第三方 cookie。jsonp
如今給 b.com 的 cookie bbb1 設置一波看看效果。網站
document.cookie="bbb1=1; SameSite=Strict"; document.cookie="bbb2=2; SameSite=Lax"; document.cookie="bbb3=3;";
注:爲了代碼簡潔,這裏就再也不設置 domain,path,expires 什麼的了。
設置完畢後,立刻打開 Chrome 調試面板看看 cookie:
咱們能夠看到這裏 cookie bbb1 的 SameSite 一列被設置了 Strict,bbb2 被設置了 Lax ,說明設置成功了。
在 a.com 頁面中試着異步請求 b.com
// a.html <img src="http://www.b.com" />
打開宇宙最強抓包工具 whistle 抓包看看 bbb1 和 bbb2 有沒有被帶到 b.com
咱們能夠看到 bbb1 和 bbb2 沒有被帶到 b.com ,只看到了 bbb3,很完美。
再看看同步請求:
這裏在 a.com 頁面上寫了一個 <a>
標籤。
// a.html <a href="http://www.b.com"> open b.com </a>
經過抓包結果咱們能夠看到 bbb2 被 設置了 SameSite=Lax 後,在同步請求的方式下,是能夠把 cookie bbb2 帶到 b.com 的,而 bbb1 依然沒有被帶上。
那麼問題來了,兩種模式咱們應該分別在什麼場景下使用呢?