asp.net-mvc
Html.AntiForgeryToken
Поиск…
Вступление
Флаг анти-подделки может использоваться для защиты вашего приложения от подделки подпроса. Чтобы использовать эту функцию, вызовите метод AntiForgeryToken из формы и добавьте атрибут ValidateAntiForgeryTokenAttribute к методу действий, который вы хотите защитить.
Создает скрытое поле формы (токен анти-подделки), который проверяется при отправке формы.
Синтаксис
- @ Html.AntiForgeryToken ()
замечания
При отправке запроса ajax с помощью токена CSRF ( __RequestVerificationToken
) убедитесь, что тип содержимого не установлен в application/json
. Если вы используете jQuery, он автоматически устанавливает тип содержимого в application/x-www-form-urlencoded
который затем распознается ASP.NET MVC.
предосторожность
Будьте осторожны при установке этого значения. Использование его ненадлежащим образом может открыть уязвимости безопасности в приложении.
Основное использование
Вспомогательный метод @Html.AntiForgeryToken()
защищает от атак с подделкой запросов на межсайтовый запрос (или CSRF).
Его можно использовать, просто используя помощник Html.AntiForgeryToken()
в одной из существующих форм и украсив соответствующее ему действие Controller с атрибутом [ValidateAntiForgeryToken]
.
Razor (YourView.cshtml)
@using (Html.BeginForm("Manage", "Account")) {
@Html.AntiForgeryToken()
<!-- ... -->
}
ИЛИ ЖЕ
<form>
@Html.AntiForgeryToken()
<!-- ... -->
</form>
Контроллер (YourController.cs)
Метод целевого действия:
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult ActionMethod(ModelObject model)
{
// ...
}
Отключить эвристический чек идентификации
Часто вы увидите исключение
Anti forgery token is meant for user "" but the current user is "username"
Это связано с тем, что токен Anti-Forgery также связан с текущим зарегистрированным пользователем. Эта ошибка появляется, когда пользователь входит в систему, но их токен по-прежнему связан с анонимным пользователем для сайта.
Есть несколько способов исправить это поведение, но если вы предпочитаете не использовать токены CSRF, связанные с входом в систему пользователя, вы можете отключить эту функцию.
Поместите эту строку в свой файл Global.asax
или аналогичную процедуру запуска приложения.
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
Проверка всех сообщений
Из-за уязвимости, вызванной CSRF, обычно считается хорошей практикой проверять AntiForgeryToken на всех HttpPosts, если нет веской причины не делать этого (некоторые технические проблемы с сообщением, есть еще один механизм аутентификации и / или пост не мутирует состояние, как сохранение в db или файл). Чтобы вы не забыли, вы можете добавить специальный файл GlobalActionFilter, который автоматически проверяет все HttpPosts, если действие не украшено специальным атрибутом «игнорировать».
[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 { }
Чтобы убедиться, что он проверяется на все запросы, просто добавьте его в свои глобальные фильтры действий
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//...
filters.Add(new ValidateAntiForgeryTokenOnAllPosts());
//...
}
}
Предварительное использование: применять фильтр Antiforgery по умолчанию для каждого POST
Мы можем забыть применить Antiforgery attribute
для каждого запроса POST
поэтому мы должны сделать это по умолчанию. В этом примере Antiforgery filter
всегда будет применяться к каждому запросу POST
.
Сначала создайте новый фильтр 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;
}
}
Затем зарегистрируйте этот настраиваемый фильтр в 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);
}
}
Итак, теперь все ваши POST
запросы защищены по умолчанию с использованием атрибутов Antiforgery, поэтому нам больше не нужно иметь атрибут [ValidateAntiForgeryToken]
для каждого метода POST.
Использование AntiForgeryToken с запросом JQuery Ajax
Сначала вы создаете форму
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
}
Метод действия
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Test(FormViewModel formData)
{
// ...
}
скрипт
<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>
Убедитесь, что contentType не настроен ни на что иное, кроме application/x-www-form-urlencoded
и если его не указан Jquery по умолчанию для application/x-www-form-urlencoded