Передача AntiForgeryToken в каждый AJAX POST реквест, генерируемый Ajax.ActionLink
Ожидает приглашения
Этот текст описывает приём, полезный при создании Ajax UI на базе библиотек Microsoft, поставляемых вместе с ASP.NET MVC.
Хорошей практикой является валидирование всех POST реквестов с помощью
Код, о котором идет речь в тексте, генерируется на базе
Самое полезное в нём то, что очень быстро им закрыть существующую XSS дыру у сайта. Предположим на вашем сайте нет защиты POST реквестов от XSS. В таком случае требуется просто скопировать этот код в основной файл JS сайта и добавить атрибут
Хорошей практикой является валидирование всех POST реквестов с помощью
AntiForgeryToken
. Это легко сделать, генерируя его с помощью вызова хелпера Html.AntiForgeryToken()
в каждой форме при рендеринге. При этом, в контролере к экшенам, валидирующим этот токен, добавляется атрибут ValidateAntiForgeryTokenAttribute
. Всё хорошо, пока не используются методы взаимодействия с сервером, которые выполняют Ajax реквесты без явного создания форм. Например, такие, как созданные с помощью хелпера Ajax.ActionLink()
. В случае использования хелпера Ajax.ActionLink
форма создается динамически перед отправкой. Стандартного способа внедрить в её тело требуемый токен нет. В описываемом случае абсолютно все экшены, принимающие POST реквесты, валидируют AntiForgeryToken
. Если ничего не предпринять, то реквесты, генерируемые кодом Ajax.ActionLink
, будут отвергнуты сервером.Код, о котором идет речь в тексте, генерируется на базе
jQuery.Ajax.Unobtrusive
и поэтому для кастомизации Ajax реквестов можно использовать стандартные jQuery методы $.ajaxSetup
и $.ajaxPrefilter
. В описываемом случае нужен именно $.ajaxPrefilter
. С его помощью можно модифицировать каждый Ajax реквест перед его отправкой. Это позволит внедрять в каждый реквест информацию о токене. Ниже показано, как именно это делается. Сам токен следует где-то взять, чтобы добавить к реквесту. В общем случае, должен быть только один токен на странице. Это решается с помощью стандартного хелпера Html.AntiForgeryToken()
. Его вызов можно разместить на странице _Layout, чтобы не делать это постоянно. Тут важно помнить, если кто-то вставит второй вызов этого хелпера, то приведёный код не сможет взять правильный вариант, т.к. берет самый первый. Ниже весь JS код, необходимый для работы описываемого подхода.function GetAntiForgeryToken() {
var tokenField = $("input[type='hidden'][name$='RequestVerificationToken']");
if (tokenField.length == 0) {
return null;
} else {
return {
name: tokenField[0].name,
value: tokenField[0].value
};
}
}
$.ajaxPrefilter(
function(options, localOptions, jqXHR) {
if (options.type !== "GET") {
var token = GetAntiForgeryToken();
if (token !== null) {
if (options.data.indexOf("X-Requested-With") === -1) {
options.data = "X-Requested-With=XMLHttpRequest" + ((options.data === "") ? "" : "&" + options.data);
}
options.data = options.data + "&" + token.name + '=' + token.value;
}
}
}
);
Самое полезное в нём то, что очень быстро им закрыть существующую XSS дыру у сайта. Предположим на вашем сайте нет защиты POST реквестов от XSS. В таком случае требуется просто скопировать этот код в основной файл JS сайта и добавить атрибут
[ValidateAntiForgeryToken]
ко всем экшенам, принимающим POST реквесты. Так же, в файл _Layout добавить Html.AntiForgeryToken()
. Теперь валидирование токена будет выполняться всегда при выполнении AJAX реквестов и разработчику не требуется постоянно помнить о добавлении токена в реквест.