asp.net-mvc
Html.AntiForgeryToken
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