CSRF攻擊通過利用瀏覽器Cookie,使得Trusted.com誤以為請求來自于Alice。那么除了Cookie外,我們是不是可以再加一層驗證來保護(hù)Alice呢?
有過網(wǎng)站開發(fā)經(jīng)驗的同學(xué)應(yīng)該記得網(wǎng)站里經(jīng)常出現(xiàn)csrf_token,這個token就是服務(wù)器在Cookie之外的第二層驗證。常見csrf_token使用方式有兩種:
對于每個request,在服務(wù)器端生成一個新的csrf_token,并將其返回在頁面的表單中。在服務(wù)器端每次接收到請求時,都會驗證表單中是否包含正確的csrf_token。由于第三方網(wǎng)站無法得知正確的csrf_token,所以無法進(jìn)行csrf攻擊。
get_token = get_random_token() return { <form> <input name=field1></input> <input type='hidden' name='csrfmiddlewaretoken' value=#{get_token()} /> </form> }
這個方法的好處是客戶端不需要支持javascript,因此通用于所有的網(wǎng)站。壞處是由于服務(wù)器端對于每個請求都會更換csrf_token,因此他需要保證用戶提交的表單是用戶最近一次請求的表單。如果用戶通過多個tab同時瀏覽該網(wǎng)站,那么往往會導(dǎo)致用戶提交的表單不是最新的那一個。
第二個方法是為每個session生成一個csrf_token,隨后將csrf_token保存到cookie中,之后通過javascript在每次請求時將csrf_token設(shè)置到http header中的X-Csrf-Token屬性中。再在服務(wù)器端比較Cookie的csrf_token與header中的token是否一致。
//當(dāng)用戶登錄時設(shè)置CookieSet-Cookie: Csrf-token=i8XNjC4b8KVok4uw5RftR38Wgp2BFwql; expires=Thu, 23-Jul-2015 10:25:33 GMT; Max-Age=31449600; Path=///當(dāng)用戶發(fā)送請求時設(shè)置Http Header中的X-Csrf-TokenX-Csrf-Token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql
有些讀者可能會問如果設(shè)置在Cookie中,那么Malicious.com豈不是可以利用Cookie中的值來設(shè)置X-Csrf-Token的值么?
其實盡管可以從Malicious.com發(fā)送給Trusted.com帶有含有csrf_token的Cookie,但是根據(jù)同源策略,Javascript無法從Malicious.com讀取或者寫入Trusted.com的Cookie。所以Malicious.com無法知道正確的csrf_token是什么,也不能夠正確的修改Http-Header的X-Csrf-Token屬性。
現(xiàn)在很多常見的web開發(fā)框架都默認(rèn)的使用Cookie-to-header方法,比如Django, Rails, Angularjs。
比如Firefox有個插件將受信任的網(wǎng)站和不信任的網(wǎng)站區(qū)分對待。然后當(dāng)用戶從不受信任的網(wǎng)站往受信任的網(wǎng)站發(fā)送信息時,將驗證信息移除。
服務(wù)器端通過檢查請求是否來自受信賴的網(wǎng)站來判斷請求是否可信。不過這個方法也有問題。有些瀏覽器出于隱私方面的考慮,會移除掉referer header。
這是比較原始的防御手段。原理是最初大量的CSRF攻擊是通過帶有src的圖片的,發(fā)送get請求來發(fā)動CSRF攻擊。所以很多服務(wù)器對于數(shù)據(jù)相關(guān)的請求改為只接受post請求。不過這個防御手段并沒有什么用,因為攻擊者可以輕松的使用javascript來模擬post請求。