防護CSRF的第四種方法?

咱們知道,通常防護CSRF有三種方法,判斷referer驗證碼tokenphp

對於判斷referer來講,雖然客戶端帶用戶狀態的跨域提交,js和as已經沒法僞造referer了;可是對於客戶端軟件和flash的提交,通常是不帶referer的,聽說一些山寨瀏覽器也不帶。那麼就須要爲此開綠燈,但這樣使得外站的flash請求僞造沒法被防護。 html

而驗證碼弊端明顯:會對用戶形成影響。 ajax

token的問題也有一些:時效性沒法保證;大型服務時,須要一臺token生成及校驗服務器;須要更改全部表單添加字段。 canvas

而最近我在作之類的防護時,想出了另一種方法,跟xeye、woyigui等人在羣裏討論了一番,認爲應該是可行的,因此拿出來分享一下,並讓其餘的牛人看看是否有什麼弊端 跨域

其實原理很是簡單,與token也差很少:當表單提交時,用js在本域添加一個臨時的cookies字段,並將過時時間設爲1秒鐘以後,而後再提交;服務端校驗有這個字段即放行,沒有則認爲是CSRF。 瀏覽器

token防csrf的原理是:沒法經過ajax等方式得到外域頁面中的token值,xmlhttprequest須要遵照瀏覽器同源策略;而臨時cookies的原理也是:cookies只能在父域和子域之間設置,也遵照同源策略。 安全

咱們能夠簡單看一個demo: 服務器

http://127.0.0.1/test.html :

<script>
function doit(){
   var expires = new Date((new Date()).getTime()+1000);
   document.cookie = "xeye=xeye; expires=" + expires.toGMTString();
}
</script>
<form action="http://127.0.0.1/test.php" name="f" id="f" onsubmit="doit();" target="if1">
<input type="button" value="normal submit" onclick="f.submit();">
<input type="button" value="with token" onclick="doit();f.submit();">
<input type="submit" value="hook submit">
</form>
<iframe src="about:blank" name="if1" id="if1"></iframe>
http://127.0.0.1/test.php:

<?php
echo "<div>Cookies</div>";
var_dump($_COOKIE);
?>

test.html爲瀏覽器端的表單,裏面有三個按鈕: cookie

第一個是正常的表單提交;第二個是添加臨時cookies後提交表單;第三個是以hook submit事件來添加臨時cookies並提交。 網絡

結果就像開頭的圖片演示那樣,正常的表單提交不會出現臨時cookies字段,第二個和第三個按鈕提交則會出現。你們能夠反覆點擊按鈕來查看結果,但須要注意時間間隔需超過1秒。(固然能夠將test.html拿到外域看看,不過要注意form的target不能指向iframe了,能夠以新窗口打開。因爲同源策略,cookies確定是帶不過去的)

不過這種方式只適用於單域名站點,或者安全需求不須要「當子域發生XSS隔離父域」。由於子域是能夠操做父域的cookies的,因此它的缺陷也比較明顯:這種方法沒法防護因爲其餘子域產生的xss所進行的表單僞造提交。而一個區分分域的自校驗token是能夠防止從其餘子域到本域的提交的。但若是對於單域而言,這種方法應該是足夠的,而且安全性可能會略大於token。

和羣裏的幾位大牛討論了一下,也認爲這種方式沒有什麼大問題,不過確實有一些小的疑問,譬如:

網絡不流暢,有延遲會不會致使cookies失效。這個顯然是不會的,由於服務端cookies是在提交請求的header中得到的。延時在服務端,不在客戶端,而1秒鐘足能夠完成set Cookies+post header整個post表單的過程。

cookies的生成依賴於js,至關於這個token是明文的?這個的確,無論採起多少種加密,只要在客戶端,就會被破解,不過無論怎樣,csrf沒法在有用戶狀態的狀況下去添加這個臨時cookies字段。雖然服務端curl等能夠,可是沒法將當前用戶的狀態也帶過去。

外站是否能夠僞造這個臨時cookies呢?目前來看至少經過as和js沒法向其餘域添加和更改cookies的,經過服務端雖然能夠僞造cookies,但得到不到目標域的用戶狀態。

若是目標域有XSS就完蛋了?恩,不過通常來講判斷referer、token和簡單的驗證碼(利用canvas識別?)也差很少完蛋了。

若是因爲某種網絡問題,得到不到cookies了呢?那麼用戶狀態也不能得到了,用戶只能再提交一次了。

ok,就這些!

說實話,這種新方法到底是否真正有效我也沒譜,說不定有某種BT的方式能夠繞過?因此share一下,你們不妨看看是否真的有效。若是真有效,那麼大概是一種最簡單的,對代碼改動最小,對服務器壓力也最小的防護CSRF的方法了。

最後感謝下woyigui,提出了不少建議呵呵!

Monyer!

相關文章
相關標籤/搜索