純前端如何抵禦CSRF攻擊?
以下是我對CSRF token的理解:
標準的CSRF抵禦機制之一就是用CSRF token,後端生成前端代碼,並在表單中加入隱藏的token,之後隨表單一起提交,後端進行token對比驗證。那麼假如前端代碼完全不受後端代碼控制呢?(更新:即前後端分離得特別清楚)就是說 後端並不干擾前端代碼的生成(也就無法加入token)。這該怎麼抵禦CSRF攻擊?之前想過使用ajax去獲取token,再放入表單中,但這好像又回到了原點——伺服器如何判斷這個獲取token請求是不是CSRF?(有點暈)
表述如有不清楚,歡迎糾正。
Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet
說個思路,除了獲取token的請求以外,其它請求都要帶上token
其它頁面雖然可以偽造獲取token的請求,但拿不到token的內容,token只要對同一客戶端 同一時段內是同一個就不怕其它頁面請求多次。
problem solvedCSRF的攻擊並不是必須有前端的參與,前端的職責只是配合後端,讓自己不被識別為攻擊者而已,所以,純前端無法抵禦CSRF。原理參見 CSRF 攻擊的應對之道 。wiki的解釋更權威全面,能翻牆的請看這裡:https://zh.wikipedia.org/wiki/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0。
axios裡面有這兩個東東。。。
// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
xsrfCookieName: "XSRF-TOKEN", // default // `xsrfHeaderName` is the name of the http header that carries the xsrf token value xsrfHeaderName: "X-XSRF-TOKEN", // defaulttoken可以生成在前端的,然後發送請求的時候把token放在header裡面一起發送。不過不是很清楚前端生成的token,是跟哪裡做對比。。。
希望有dalao能解釋下前端生成token的姿勢= =。
Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a malicious web site, email, blog, instant message, or program causes a user』s web browser to perform an unwanted action on a trusted site for which the user is currently authenticated.
CSRF很重要的一個起因就是完全對用戶的信任。如果後端完全不能干涉CSRF判斷(header,cookie等等),而僅僅接受數據這的話就意味著它對提交的數據要完全信任,這個明顯是和防範CSRF的原則相背的。
我們總不能用前端驗證用戶吧。。。
那麼假如前端代碼完全不受後端代碼控制呢?(更新:即前後端分離得特別清楚)就是說 後端並不干擾前端代碼的生成(也就無法加入token)。這該怎麼抵禦CSRF攻擊?
So,應該只能純後端。。。不能純前端。
後端每次返回頁面都random一個cookie,然後提交表單時校驗cookie即可。
關於防範跨站攻擊的一點思考:
防範跨站攻擊的關鍵是防止單一依靠Cookie認證,因為瀏覽器的弊端,跨站攻擊者雖然不可能「獲得」你的Cookie但是可以用過偽造表單的方式「利用」你的Cookie。而防範的要點就是不僅僅在Cookie中存儲Token,還同時通過其他方式提交Token,如表單、Header、參數。因為攻擊者無法知道你的Token,所以他無法在表單、Header、參數中提供正確的Token。
關於這一點,其實前後端分離的網站和傳統的網站是沒有什麼本質區別的,只需要在登入時更新Token並返回客戶端即可,攻擊者是無法提供登入信息的,所以無法取得你的Token。接下來,還可以為Token設置失效時間,失效後必須拿舊Token換新Token。在這種意義上,舊Token其實也是一種登入信息了。
有些回答根本不對呀!
簡單說就是按照題主的情況就是,在發出登錄請求的時候(登錄授權的時候ajax請求),後端需要在 response 設置 xsrf-cookie-token,以後所有的表單請求都要附帶這個 Token,後端驗證這個 Token 即可防範 XSRF。
XSRF(CSRF) 攻擊的原理是什麼?就是攻擊者能猜測出所有的需要提交的內容,所以所有的解決方案就是加一個攻擊者也不知道隨機值發送給後端驗證就可以防範,還是需要後端驗證。
有很多解決方案,cookie-session,很不友好的所有表單都得填寫驗證碼,還有一種很少人知道 JSON Web Token。
驗證碼(圖形或者手機)這種就不說了吧,這個在互聯網場景中因為用戶體驗原因幾乎沒有應用的。
題主可以用這種 cookie-sseion 方式實現單頁應用的防範XSRF。首先要知道直接讓後端驗證 cookie 是不可取的,因為所有請求都會自動附帶請求所在域的 cookie。
正確的方式是當用戶進行登錄請求的時候,這時候後端應該把包含 xsrf 欄位的 cookie 保存在 session 中並且返還給前端,前端需要獲取到cookie 中的值並且能放入 ajax 請求頭(HTTP request header)中,後端把這個值與 session 中的相應值進行判斷就可以了,根據跨域不可訪問不同域的 cookie ,攻擊者也很難猜測出 xsrf 的值,那麼這樣就防範了 xsrf 攻擊。
所以這裡對 xsrf cookie 不能設置 httpOnly(當然就會有 XSS 問題,後面會提),同時提一句所以的 Token 必須得讓後端設置 expire 過期時間。
這個 axios 就提供了這個功能,只要設置約定好 xsrf cookie欄位名就可以了,這也是業界最流行的方式。
如果不是單頁應用都是後端在表單中加入一個隱藏的表單域。
&
當然還有JWT,這個主要應用場景是 app,因為 app 通常沒有 Cookie,當然也有應用到 Web 中的,要講這個就有點多了,和上述也差不多,這裡簡單說說,感興趣的可以谷歌搜索。JWT應用了哈希簽名的密碼學技術,相比 cookie-session 的方式就是服務端可以不用(在內存或者緩存)存放 session,能節省存儲資源,不過同時伺服器需要通過計算來驗證也浪費了計算資源。
JWT 就是服務端和客戶端約定好一個 Token 格式,最後用密鑰進行簽名 base64 編碼後放入請求頭即可,客戶端存放這個簽名的內容通常會放在 localstorage 中,也有放在 cookie 中的。
現有的產品為了更安全還需要考慮 XSS 攻擊,這個就是有些惡意腳本或者插件不存在跨域問題,所以能獲取到 cookie 和 localstorage 的值。
很安全的方式就是把 XSRF Token 放入 JWT 中,並且把 JWT 存在在設置 httpOnly 的 cookie 中,然後把 XSRF Token 再設置 httpOnly = false 的 cookie 中,請求都放入請求頭。伺服器端可以直接驗證 JWT 中 XSRF 的值 和 XSRF 的值即可。因為用了哈希密鑰簽名的技術,這個可以防止篡改。
有時間我再把 JWT 補充到答案中。
通過這兩天的探索,發現了一個解決辦法:
使用token based authentication,這個token是在用戶登錄時發送給瀏覽器的,通過js保存在客戶端,之後所有請求都必須帶上這個token,伺服器收到後對這個token進行解密驗證(而不是對比驗證,不需要在伺服器保存該token)
不同於CSRF token,上述的token內容並不是簡單的隨機字元串,而是包含內容並經過加密(比如jwt,有興趣的去搜索一下)
注意,這種方法已經完全不需要伺服器保存一份token副本(而我在題目中提及的CSRF token方法針對的仍舊是傳統的使用session cookie記錄用戶狀態信息的解決方案。),因此即使前後端完全分離,token也可以通過登錄時的request-response傳遞。
至於CSRF攻擊者,由於他們沒有用戶的賬號密碼(如果有的話,那何需CSRF),因此無法登錄也就無法獲取token。
關於token based authentication和jwt,有興趣的可以自行搜索更多文章查看。
如有表述錯誤,歡迎糾正。
歡迎分享和討論更多解決方案。拙見!你用ajax獲取token,首先這個ajax也要帶上token,純前端的意思是與後端不進行交互,那麼回到token的目的是什麼,隨機性且可驗證用戶身份,那麼需要在與後端不進行交互的情況下進行驗證用戶身份,我咋感覺基本不可能?另外,csrf漏洞發生時,控制者不就已經控制了你的前端?那麼所有在前端做的驗證不就形同虛設了嗎?
推薦閱讀:
※你在什麼情況下會選擇使用 Backbone.js 或 AngularJS?
※shadow dom可以做什麼用?
※現在jQuery不流行了嗎?
※自學前端已經兩個月了,不知道學到什麼程度才能有一份工作!?
※10年網路遊戲前端程序轉型方向何在?