Szukaj…


Wprowadzenie

Token zapobiegający fałszowaniu może pomóc w ochronie aplikacji przed fałszowaniem żądań w różnych witrynach. Aby użyć tej funkcji, wywołaj metodę AntiForgeryToken z formularza i dodaj atrybut ValidateAntiForgeryTokenAttribute do metody akcji, którą chcesz chronić.

Generuje ukryte pole formularza (token zapobiegający fałszerstwu), które jest sprawdzane podczas przesyłania formularza.

Składnia

  • @ Html.AntiForgeryToken ()

Uwagi

Przesyłając żądanie ajax z tokenem CSRF ( __RequestVerificationToken ), upewnij się, że typ zawartości nie jest ustawiony na application/json . Jeśli używasz jQuery, automatycznie ustawia typ zawartości na application/x-www-form-urlencoded który jest następnie rozpoznawany przez ASP.NET MVC.

Uwaga

Zachowaj ostrożność podczas ustawiania tej wartości. Niewłaściwe użycie może otworzyć luki w zabezpieczeniach aplikacji.

Podstawowe użycie

Metoda pomocnicza @Html.AntiForgeryToken() chroni przed atakami fałszowania żądań między witrynami (lub CSRF).

Można go użyć, po prostu używając pomocnika Html.AntiForgeryToken() w jednej z istniejących formularzy i dekorując odpowiednią akcję kontrolera atrybutem [ValidateAntiForgeryToken] .

Razor (YourView.cshtml)

@using (Html.BeginForm("Manage", "Account")) {
    @Html.AntiForgeryToken()  
    <!-- ... -->
}

LUB

<form>
    @Html.AntiForgeryToken()
    <!-- ... -->
</form>

Kontroler (YourController.cs)

Metoda działania docelowego:

[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult ActionMethod(ModelObject model)
{
    // ...
}

Wyłącz kontrolę heurystyczną tożsamości

Często widzisz wyjątek

Anti forgery token is meant for user "" but the current user is "username"

Wynika to z faktu, że token Anti-Forgery jest również powiązany z bieżącym zalogowanym użytkownikiem. Ten błąd pojawia się, gdy użytkownik loguje się, ale jego token jest nadal powiązany z byciem anonimowym użytkownikiem witryny.

Istnieje kilka sposobów na naprawienie tego zachowania, ale jeśli wolisz, aby tokeny CSRF nie były powiązane ze stanem zalogowania użytkownika, możesz wyłączyć tę funkcję.

Umieść ten wiersz w pliku Global.asax lub podobnej logice uruchamiania aplikacji.

AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;

Sprawdzanie poprawności wszystkich postów

Ze względu na podatność spowodowaną przez CSRF, ogólnie uważa się za dobrą praktykę sprawdzanie AntiForgeryToken na wszystkich HttpPosts, chyba że istnieje uzasadniony powód, aby tego nie robić (jakiś problem techniczny z postem, istnieje inny mechanizm uwierzytelniania i / lub post nie powoduje mutacji stanu, np. zapisywanie w bazie danych lub pliku). Aby upewnić się, że nie zapomnisz, możesz dodać specjalny filtr GlobalActionFilter, który automatycznie sprawdza wszystkie HttpPosts, chyba że akcja jest ozdobiona specjalnym atrybutem „ignoruj”.

[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {
            bool skipCheck = filterContext.ActionDescriptor.IsDefined(typeof(DontCheckForAntiForgeryTokenAttribute), true)
                || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(DontCheckForAntiForgeryTokenAttribute), true);

            if (skipCheck)
                return;


            //  Ajax POSTs and normal form posts have to be treated differently when it comes
            //  to validating the AntiForgeryToken
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value
                    : null;

                AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

/// <summary>
/// this should ONLY be used on POSTS that DO NOT MUTATE STATE
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class DontCheckForAntiForgeryTokenAttribute : Attribute { }

Aby upewnić się, że sprawdzane są wszystkie żądania, wystarczy dodać go do globalnych filtrów akcji

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //...
        filters.Add(new ValidateAntiForgeryTokenOnAllPosts());
        //...
    }
}

Zaawansowane wykorzystanie: Zastosuj domyślny filtr przeciwmgłowy dla każdego testu POST

Możemy zapomnieć zastosować Antiforgery attribute dla każdego POST więc powinniśmy Antiforgery attribute go domyślnie. Ta próbka upewni się, że Antiforgery filter będzie zawsze stosowany do każdego POST .

Najpierw utwórz nowy filtr AntiForgeryTokenFilter :

//This will add ValidateAntiForgeryToken Attribute to all HttpPost action methods
public class AntiForgeryTokenFilter : IFilterProvider
{
    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        List<Filter> result = new List<Filter>();

        string incomingVerb = controllerContext.HttpContext.Request.HttpMethod;

        if (String.Equals(incomingVerb, "POST", StringComparison.OrdinalIgnoreCase))
        {
            result.Add(new Filter(new ValidateAntiForgeryTokenAttribute(), FilterScope.Global, null));
        }

        return result;
    }
}

Następnie zarejestruj ten filtr niestandardowy w MVC, Application_Start:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {    
        //Cactch generic error
        filters.Add(new HandleErrorAttribute());

        //Anti forgery token hack for every post request
        FilterProviders.Providers.Add(new AntiForgeryTokenFilter());            
    }
}  



public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

Tak więc teraz wszystkie twoje żądania POST są domyślnie chronione przy użyciu atrybutów Antiforgery, więc nie musimy już mieć atrybutu [ValidateAntiForgeryToken] dla każdej metody POST.

Używanie AntiForgeryToken z żądaniem Jquery Ajax

Najpierw utwórz formularz

@using (Html.BeginForm())
{
  @Html.AntiForgeryToken()
}

Metoda działania

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Test(FormViewModel formData)
{
    // ...
}

Scenariusz

<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
var formData = new FormData($('form')[0]);
$.ajax({
    method: "POST",
    url: "/demo/test",
    data: formData ,
    success: function (data) {
  console.log(data);
    },
    error: function (jqXHR, textStatus, errorThrown) {
        console.log(errorThrown);
    }
})
</script>

Upewnij się, że contentType nie jest ustawiony na nic oprócz application/x-www-form-urlencoded a jeśli nie jest określony, Jquery domyślnie przyjmuje wartość application/x-www-form-urlencoded



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow