ASP.NET MVC Uygulamasında Siteler Arası İstek Sahteciliği (CSRF) Saldırılarını Önleme

Siteler Arası İstek Sahteciliği (CSRF), kötü amaçlı bir sitenin kullanıcının şu anda oturum açtığı güvenlik açığı olan bir siteye istek gönderdiği bir saldırıdır

CsRF saldırısı örneği aşağıda verilmiştir:

  1. Bir kullanıcı form kimlik doğrulaması kullanarak oturum www.example.com açar.

  2. Sunucu kullanıcının kimliğini doğrular. Sunucudan gelen yanıt bir kimlik doğrulama tanımlama bilgisi içerir.

  3. Kullanıcı oturumu kapatmadan kötü amaçlı bir web sitesini ziyaret eder. Bu kötü amaçlı site aşağıdaki HTML formunu içerir:

    <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önderildiğini göreceksiniz. Bu, CSRF'nin "siteler arası" bölümüdür.

  4. Kullanıcı gönder düğmesine tıklar. Tarayıcı, istekle birlikte kimlik doğrulama tanımlama bilgisini içerir.

  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 izin verilen her şeyi yapabilir.

Bu örnekte kullanıcının form düğmesine tıklaması gerekse de, kötü amaçlı sayfa formu otomatik olarak gönderen bir betiği kolayca çalıştırabilir. Ayrıca, kötü amaçlı site bir "https://" isteği gönderebileceğinden SSL kullanılması CSRF saldırısını engellemez.

Genellikle, tarayıcılar tüm ilgili tanımlama bilgilerini hedef web sitesine gönderdiğinden, kimlik doğrulaması için tanımlama bilgileri kullanan web sitelerine CSRF saldırıları yapılabilir. Ancak CSRF saldırıları, tanımlama bilgilerini kötüye kullanmakla sınırlı değildir. Örneğin, Temel ve Özet kimlik doğrulaması da savunmasızdır. Bir kullanıcı Temel veya Özet kimlik doğrulamasıyla oturum açtığında. oturum bitene kadar tarayıcı kimlik bilgilerini otomatik olarak gönderir.

Sahteciliğe Karşı Koruma Belirteçleri

CSRF saldırılarını önlemeye yardımcı olmak için ASP.NET MVC, istek doğrulama belirteçleri olarak da adlandırılan sahtecilik önleme belirteçlerini kullanır.

  1. İstemci form içeren bir HTML sayfası istemektedir.
  2. Sunucu yanıtta iki belirteç içerir. Bir belirteç tanımlama bilgisi olarak gönderilir. Diğeri gizli bir form alanına yerleştirilir. Belirteçler rastgele oluşturulur, böylece bir saldırgan değerleri tahmin edemez.
  3. İstemci formu gönderdiğinde, her iki belirteci de sunucuya geri göndermelidir. İstemci tanımlama bilgisi belirtecini tanımlama bilgisi olarak, form belirtecini de form verilerinin içine gönderir. (Kullanıcı formu gönderdiğinde tarayıcı istemcisi bunu otomatik olarak yapar.)
  4. bir istek her iki belirteci de içermiyorsa, sunucu isteğe izin vermez.

Gizli form belirteci içeren bir HTML formu örneği aşağıda verilmiştir:

<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ığından sahteciliğe karşı koruma belirteçleri çalışır. (Aynı kaynak ilkeleri , iki farklı site üzerinde barındırılan belgelerin birbirlerinin içeriğine erişmesini engeller. Bu nedenle, önceki örnekte kötü amaçlı sayfa example.com istek gönderebilir, ancak yanıtı okuyamaz.)

CSRF saldırılarını önlemek için, kullanıcı oturum açtıktan sonra tarayıcının kimlik bilgilerini sessizce gönderdiği herhangi bir kimlik doğrulama protokolüyle sahteciliğe karşı koruma belirteçlerini kullanın. Buna form kimlik doğrulaması gibi tanımlama bilgisi tabanlı kimlik doğrulama protokollerinin yanı sıra Temel ve Özet kimlik doğrulaması gibi protokoller dahildir.

Güvenli olmayan yöntemler (POST, PUT, DELETE) için sahteciliğe karşı koruma belirteçleri gerektirmelisiniz. Ayrıca, güvenli yöntemlerin (GET, HEAD) herhangi bir yan etkisi olmadığından emin olun. Ayrıca, CORS veya JSONP gibi etki alanları arası desteği etkinleştirirseniz GET gibi güvenli yöntemler bile CSRF saldırılarına karşı savunmasız olabilir ve saldırganın hassas olabilecek verileri okumasına olanak tanır.

ASP.NET MVC'de Sahteciliğe Karşı Koruma Belirteçleri

Sahteciliğe karşı koruma belirteçlerini razor sayfasına eklemek için HtmlHelper.AntiForgeryToken yardımcı yöntemini kullanın:

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

Bu yöntem gizli form alanını ekler ve tanımlama bilgisi belirtecini de ayarlar.

CSRF ve AJAX Anti-CSRF

Form belirteci AJAX istekleri için sorun olabilir çünkü bir AJAX isteği HTML form verileri değil JSON verileri gönderebilir. Bir çözüm, belirteçleri özel bir HTTP üst bilgisinde göndermektir. Aşağıdaki kod, belirteçleri oluşturmak için Razor söz dizimini kullanır ve ardından belirteçleri bir AJAX isteğine ekler. Belirteçler , AntiForgery.GetTokens çağrılarak sunucuda oluşturulur.

<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 işlerken, istek üst bilgisindeki belirteçleri ayıklayın. Ardından belirteçleri doğrulamak için AntiForgery.Validate yöntemini çağırın. Belirteçler geçerli değilse Validate yöntemi bir özel durum oluşturur.

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