在ASP.NET Web API中防止跨站點請求偽造(CSRF)攻擊


定義

跨站點請求偽造(CSRF)是一種惡意站點向用戶當前登錄的易受攻擊的站點發送請求的攻擊方式。

以下是CSRF攻擊的示例(必須具備的條件):

  1. 用戶使用表單驗證登錄 www.example.com。
  2. 服務器驗證用戶,響應(Response)包含了一個認證cookie。
  3. 用戶沒有注銷,然后訪問了惡意網站。此惡意網站包含以下HTML表單:

    1 <h1>You Are a Winner!</h1>
    2   <form action="http://example.com/api/account" method="post">
    3     <input type="hidden" name="Transaction" value="withdraw" />
    4     <input type="hidden" name="Amount" value="1000000" />
    5   <input type="submit" value="Click Me"/>
    6 </form>

     

    請注意,表單的Action是Post到易受攻擊的網站,而不是惡意網站。這是CSRF的“跨站點”部分

  4. 用戶點擊提交按鈕。瀏覽器請求包含身份驗證cookie。
  5. 請求在具有用戶身份驗證上下文的服務器上運行,並且可以做任何經過身份驗證的用戶才能被允許做的操作。

雖然此示例需要用戶主動單擊表單按鈕,但是惡意頁面可以輕松運行自動提交表單的腳本。此外,使用SSL不能阻止CSRF攻擊,因為惡意站點也可以發送“https://”請求。

通常,針對使用Cookie進行身份驗證的網站可能會發生CSRF攻擊,因為瀏覽器會將所有相關的Cookie發送到目標網站。然而,CSRF攻擊並不僅限於利用Cookie。例如,BasicDigest身份驗證也很脆弱。用戶使用“Basic”或“Digest”身份驗證登錄后,瀏覽器會自動發送憑證直到會話結束。

 

防偽令牌(Anti-Forgery Tokens)

為了幫助防止CSRF攻擊,ASP.NET MVC使用防偽令牌(Anti-Forgery Tokens),也稱為請求驗證令牌

  1. 客戶端請求包含表單的HTML頁面。
  2. 服務器在響應中包含兩個令牌。一個令牌作為一個Cookie發送。另一個放置在隱藏的表單字段中。令牌隨機生成,使攻擊者無法猜測令牌值。
  3. 當客戶端提交表單時,它必須將兩個令牌發送回服務器。客戶端將Cookie令牌作為cookie發送,並在表單數據中發送表單令牌。(瀏覽器客戶端在用戶提交表單時自動執行此操作。)
  4. 如果請求不包含這兩個令牌,則服務器不允許該請求。

以下是具有隱藏表單令牌的HTML表單的示例:

<form action="/Home/Test" method="post">
    <input name="__RequestVerificationToken" type="hidden" value="6fGBtLZmVBZ59oUad1Fr33BuPxANKY9q3Srr5y[...]" />  
    <input type="submit" value="Submit" />
</form>

防偽令牌的工作原理是惡意頁面無法讀取用戶的令牌,因為有同源策略。(同源策略可以防止兩個不同站點上托管的文件訪問對方的內容,所以在前面的例子中,惡意頁面可以發送請求到example.com,但不能讀取響應。)

為了防止CSRF攻擊,任何在用戶登錄后瀏覽器默認發送憑據的身份驗證協議都應使用防偽令牌。包括基於cookie的身份驗證協議,如表單身份驗證以及BasicDigest(摘要)身份驗證等協議。

您應該對任何非安全方法(POST,PUT,DELETE)要求防偽令牌。另外,確保安全的方法(GET,HEAD)沒有任何副作用。此外,如果您啟用跨域支持(如CORS或JSONP),則甚至安全的方法(如GET)也可能容易受到CSRF攻擊的攻擊,從而允許攻擊者讀取潛在的敏感數據。

 

ASP.NET MVC中的防偽令牌

要將防偽令牌添加到Razor頁面,請使用HtmlHelper.AntiForgeryToken幫助方法:

@using (Html.BeginForm("Manage", "Account")) { @Html.AntiForgeryToken() }

此方法添加隱藏表單字段,並設置cookie令牌。

 

Anti-CSRF 和 AJAX

表單令牌可能是AJAX請求的一個問題,因為AJAX請求可能會發送JSON數據,而不是HTML表單數據。一個解決方案是將Token發送到自定義HTTP標頭。以下代碼使用Razor語法生成令牌,然后將令牌添加到AJAX請求。令牌通過調用AntiForgery.GetTokens在服務器端生成。

<script> @functions{ public string TokenHeaderValue() { string cookieToken, formToken; AntiForgery.GetTokens(null, out cookieToken, out formToken); return cookieToken + ":" + formToken; } } $.ajax("api/values", { type: "post", contentType: "application/json", data: { }, // JSON data goes here
        dataType: "json", headers: { 'RequestVerificationToken': '@TokenHeaderValue()' } }); </script>

 

處理請求時,從請求頭中提取令牌。然后調用AntiForgery.Validate方法來驗證令牌。如果令牌無效,該驗證方法將引發異常。

void ValidateRequestHeader(HttpRequestMessage request) { string cookieToken = ""; string formToken = ""; IEnumerable<string> tokenHeaders; if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders)) { string[] tokens = tokenHeaders.First().Split(':'); if (tokens.Length == 2) { cookieToken = tokens[0].Trim(); formToken = tokens[1].Trim(); } } AntiForgery.Validate(cookieToken, formToken); }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM