1. 程式人生 > >什麼是CSRF攻擊,如何在ASP.NET MVC網站中阻止這種攻擊?

什麼是CSRF攻擊,如何在ASP.NET MVC網站中阻止這種攻擊?

1   什麼是CSRF,如何防治? Cross-site request forgery 1.1 例子 假如一家銀行用以執行轉賬操作的URL地址如下: http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName 那麼,一個惡意攻擊者可以在另一個網站上放置如下程式碼: <img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman"> 如果有賬戶名為Alice的使用者訪問了惡意站點,而她之前剛訪問過銀行不久,登入資訊尚未過期,那麼她就會損失1000資金。 這種惡意的網址可以有很多種形式,藏身於網頁中的許多地方。此外,攻擊者也不需要控制放置惡意網址的網站。例如他可以將這種地址藏在論壇,部落格等任何使用者生成內容的網站中。這意味著如果伺服器端沒有合適的防禦措施的話,使用者即使訪問熟悉的可信網站也有受攻擊的危險。 透過例子能夠看出,攻擊者並不能通過CSRF攻擊來直接獲取使用者的賬戶控制權,也不能直接竊取使用者的任何資訊。他們能做到的,是欺騙使用者瀏覽器,讓其以使用者的名義執行操作。 1.2 防禦措施
1.2.1 檢查Referer欄位 HTTP頭中有一個Referer欄位,這個欄位用以標明請求來源於哪個地址。在處理敏感資料請求時,通常來說,Referer欄位應和請求的地址位於同一域名下。以上文銀行操作為例,Referer欄位地址通常應該是轉賬按鈕所在的網頁地址,應該也位於www.examplebank.com之下。而如果是CSRF攻擊傳來的請求,Referer欄位會是包含惡意網址的地址,不會位於www.examplebank.com之下,這時候伺服器就能識別出惡意的訪問。 這種辦法簡單易行,工作量低,僅需要在關鍵訪問處增加一步校驗。但這種辦法也有其侷限性,因其完全依賴瀏覽器傳送正確的Referer欄位。雖然http協議對此欄位的內容有明確的規定,但並無法保證來訪的瀏覽器的具體實現,亦無法保證瀏覽器沒有安全漏洞影響到此欄位。並且也存在攻擊者攻擊某些瀏覽器,篡改其Referer欄位的可能。 1.2.2 新增校驗token
由於CSRF的本質在於攻擊者欺騙使用者去訪問自己設定的地址,所以如果要求在訪問敏感資料請求時,要求使用者瀏覽器提供不儲存在cookie中,並且攻擊者無法偽造的資料作為校驗,那麼攻擊者就無法再執行CSRF攻擊。這種資料通常是表單中的一個數據項。伺服器將其生成並附加在表單中,其內容是一個偽亂數。當客戶端通過表單提交請求時,這個偽亂數也一併提交上去以供校驗。正常的訪問時,客戶端瀏覽器能夠正確得到並傳回這個偽亂數,而通過CSRF傳來的欺騙性攻擊中,攻擊者無從事先得知這個偽亂數的值,伺服器端就會因為校驗token的值為空或者錯誤,拒絕這個可疑請求。 1.3 攻擊細節 簡單的身份驗證只能保證請求發自某個使用者的瀏覽器,卻不能保證請求本身是使用者自願發出的。
1.4 ASP.NET MVC 中解決方案 思路如下: Anti-Forgery Token主要使用post方法來驗證post資料的資料來源。  在這個方法中,對於每個頁面請求,web伺服器首先發送一個cookie到客戶端瀏覽器。 當下一個request到來時,使用cookie來驗證客戶端的 authentication。 如果request來自未授權的站點。cookie會是null或者無效的; 解決方案:Controller上面,加上 [ValidateAntiForgeryToken];  View中加上 @Html.AntiForgeryToken(),就能解決問題; 範例程式碼 Controller [__strong__][ValidateAntiForgeryToken] public class UserController : Controller     {         public ActionResult DeleteUser()         {             var userId = (int)Session["userId"];             DeleteUserFromDb(userId);//Function for deleting the user from Database             return View();          }     } View @using (Html.BeginForm("DeleteUser", "User")) {     @Html.AntiForgeryToken()     <input type="submit" value="Delete My Account" /> }