ASP.NET MVC uygulamasında siteler arası Istek forgery (CSRF) saldırılarını önlemePreventing Cross-Site Request Forgery (CSRF) Attacks in ASP.NET MVC Application

, Mike te sonby Mike Wasson

Siteler arası Istek sahteciliği (CSRF), kötü niyetli bir sitenin kullanıcının şu anda oturum açtığı bir güvenlik açığı olan siteye istek gönderdiği bir saldırıya neden olurCross-Site Request Forgery (CSRF) is an attack where a malicious site sends a request to a vulnerable site where the user is currently logged in

CSRF saldırılarına bir örnek aşağıda verilmiştir:Here is an example of a CSRF attack:

  1. Kullanıcı, Forms kimlik doğrulaması kullanarak www.example.com oturum açar.A user logs into www.example.com using forms authentication.

  2. Sunucu, kullanıcının kimliğini doğrular.The server authenticates the user. Sunucudan gelen yanıt bir kimlik doğrulama tanımlama bilgisi içerir.The response from the server includes an authentication cookie.

  3. Oturum açmadan, Kullanıcı kötü amaçlı bir Web sitesi ziyaret ettiğinde.Without logging out, the user visits a malicious web site. Bu kötü amaçlı site aşağıdaki HTML biçimini içerir:This malicious site contains the following HTML form:

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

    Form eyleminin kötü amaçlı siteye değil, güvenlik açığı bulunan siteye gönderdiğine dikkat edin.Notice that the form action posts to the vulnerable site, not to the malicious site. Bu, CSRF 'nin "siteler arası" parçasıdır.This is the "cross-site" part of CSRF.

  4. Kullanıcı Gönder düğmesine tıklar.The user clicks the submit button. Tarayıcı, istekle kimlik doğrulama tanımlama bilgisini içerir.The browser includes the authentication cookie with the request.

  5. İstek, kullanıcının kimlik doğrulama bağlamıyla sunucuda çalışır ve kimliği doğrulanmış bir kullanıcının yapmasına izin verilen her şeyi yapabilir.The request runs on the server with the user's authentication context, and can do anything that an authenticated user is allowed to do.

Bu örnekte kullanıcının form düğmesine tıklamasa da kötü amaçlı sayfa yalnızca formu otomatik olarak gönderen bir betiği kolayca çalıştırabilir.Although this example requires the user to click the form button, the malicious page could just as easily run a script that submits the form automatically. Üstelik, SSL kullanmak CSRF saldırılarına engel değildir çünkü kötü amaçlı site "https://" isteği gönderebilir.Moreover, using SSL does not prevent a CSRF attack, because the malicious site can send an "https://" request.

Genellikle, tarayıcılar tüm ilgili tanımlama bilgilerini hedef Web sitesine gönderdikleri için kimlik bilgilerini kullanan Web sitelerine karşı CSRF saldırıları mümkündür.Typically, CSRF attacks are possible against web sites that use cookies for authentication, because browsers send all relevant cookies to the destination web site. Ancak, CSRF saldırıları, tanımlama bilgilerini kötüye ile sınırlı değildir.However, CSRF attacks are not limited to exploiting cookies. Örneğin, temel ve Özet kimlik doğrulaması da savunmasız olacaktır.For example, Basic and Digest authentication are also vulnerable. Bir Kullanıcı temel veya Özet kimlik doğrulamasıyla oturum açtıktan sonra.After a user logs in with Basic or Digest authentication. tarayıcı, oturum sona erene kadar kimlik bilgilerini otomatik olarak gönderir.the browser automatically sends the credentials until the session ends.

Korunma belirteçleriAnti-Forgery Tokens

ASP.NET MVC, CSRF saldırılarını önlemeye yardımcı olmak için, istek doğrulama belirteçleriolarak da adlandırılan, güvenlik yumuşatma belirteçlerini kullanır.To help prevent CSRF attacks, ASP.NET MVC uses anti-forgery tokens, also called request verification tokens.

  1. İstemci, form içeren bir HTML sayfası ister.The client requests an HTML page that contains a form.
  2. Sunucu, yanıtta iki belirteç içerir.The server includes two tokens in the response. Bir belirteç tanımlama bilgisi olarak gönderilir.One token is sent as a cookie. Diğeri gizli form alanına yerleştirilir.The other is placed in a hidden form field. Belirteçler rastgele oluşturulur, böylece bir saldırgan değerleri tahmin edemez.The tokens are generated randomly so that an adversary cannot guess the values.
  3. İstemci formu gönderdiğinde, her iki belirteci sunucuya geri göndermelidir.When the client submits the form, it must send both tokens back to the server. İstemci tanımlama bilgisi belirtecini tanımlama bilgisi olarak gönderir ve form belirtecini form verileri içine gönderir.The client sends the cookie token as a cookie, and it sends the form token inside the form data. (Kullanıcı formu gönderdiğinde bir tarayıcı istemcisi bunu otomatik olarak yapar.)(A browser client automatically does this when the user submits the form.)
  4. Bir istek her iki belirteci de içermiyorsa, sunucu isteğe izin vermez.If a request does not include both tokens, the server disallows the request.

Gizli form belirtecine sahip HTML biçimine bir örnek aşağıda verilmiştir:Here is an example of an HTML form with a hidden form token:

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

Kötü amaçlı sayfa, aynı kaynak ilkeleri nedeniyle kullanıcının belirteçlerini okuyamadığı için, karşı koruma belirteçleri çalışır.Anti-forgery tokens work because the malicious page cannot read the user's tokens, due to same-origin policies. (Aynı kaynak ilkeleri iki farklı sitede barındırılan belgelerin birbirlerinin içeriğine erişmesini önler.(Same-origin policies prevent documents hosted on two different sites from accessing each other's content. Bu nedenle, kötü amaçlı sayfa example.com 'e istek gönderebilir, ancak yanıtı okuyamıyor.)So in the earlier example, the malicious page can send requests to example.com, but it cannot read the response.)

CSRF saldırılarını engellemek için, tarayıcının Kullanıcı oturum açtıktan sonra kimlik bilgilerini sessizce gönderdiği kimlik doğrulama protokolleriyle karşı koruma belirteçleri kullanın.To prevent CSRF attacks, use anti-forgery tokens with any authentication protocol where the browser silently sends credentials after the user logs in. Bu, Forms kimlik doğrulaması ve temel ve Özet kimlik doğrulaması gibi protokollerin yanı sıra tanımlama bilgisi tabanlı kimlik doğrulama protokollerini içerir.This includes cookie-based authentication protocols, such as forms authentication, as well as protocols such as Basic and Digest authentication.

Güvenli olmayan Yöntemler (POST, PUT, DELETE) için koruma yumuşatma gerekli olmalıdır.You should require anti-forgery tokens for any nonsafe methods (POST, PUT, DELETE). Ayrıca, güvenli yöntemlerin (GET, HEAD) hiç yan etkisi olmadığından emin olun.Also, make sure that safe methods (GET, HEAD) do not have any side effects. Üstelik, CORS veya JSONP gibi etki alanları arası desteğini etkinleştirirseniz, GET gibi güvenli yöntemler de CSRF saldırılarına açıktır ve bu da saldırganın potansiyel olarak hassas verileri okumasına olanak tanır.Moreover, if you enable cross-domain support, such as CORS or JSONP, then even safe methods like GET are potentially vulnerable to CSRF attacks, allowing the attacker to read potentially sensitive data.

ASP.NET MVC 'de Anti-forgery belirteçleriAnti-Forgery Tokens in ASP.NET MVC

Bir Razor sayfasına korsanlığa karşı koruma belirteçleri eklemek için HtmlHelper. AntiForgeryToken yardımcı yöntemini kullanın:To add the anti-forgery tokens to a Razor page, use the HtmlHelper.AntiForgeryToken helper method:

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

Bu yöntem gizli form alanını ekler ve tanımlama bilgisi belirtecini de ayarlar.This method adds the hidden form field and also sets the cookie token.

Anti-CSRF ve AJAXAnti-CSRF and AJAX

Bir AJAX isteği HTML form verileri değil JSON verisi gönderebildiğinden, form belirteci, AJAX istekleri için bir sorun olabilir.The form token can be a problem for AJAX requests, because an AJAX request might send JSON data, not HTML form data. Tek bir çözüm, belirteçleri özel bir HTTP üst bilgisinde göndermektir.One solution is to send the tokens in a custom HTTP header. Aşağıdaki kod belirteçleri oluşturmak için Razor söz dizimi kullanır ve ardından belirteçleri bir AJAX isteğine ekler.The following code uses Razor syntax to generate the tokens, and then adds the tokens to an AJAX request. Belirteçler, Antiforgery. GetTokensçağırarak sunucuda oluşturulur.The tokens are generated at the server by calling 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>

İsteği tamamladığınızda, belirteçleri istek başlığından ayıklayın.When you process the request, extract the tokens from the request header. Ardından, belirteçleri doğrulamak için Antiforgery. Validate metodunu çağırın.Then call the AntiForgery.Validate method to validate the tokens. Belirteçler geçerli değilse Validate yöntemi bir özel durum oluşturur.The Validate method throws an exception if the tokens are not valid.

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);
}