Защита CSRF в AJAX-запросах с использованием MVC2 - PullRequest
8 голосов
/ 28 февраля 2010

Страница, которую я создаю, сильно зависит от AJAX.По сути, есть только одна «страница», и каждая передача данных обрабатывается через AJAX.Поскольку чрезмерное оптимистическое кэширование на стороне браузера приводит к странным проблемам (данные не перезагружаются), я должен выполнить все запросы (также считывает) с помощью POST - что вызывает перезагрузку.

Теперь я хочу предотвратить защиту страницы от CSRF,С отправкой формы, использование Html.AntiForgeryToken() работает аккуратно, но в AJAX-запросе, я думаю, мне придется добавлять токен вручную?Есть ли что-нибудь из коробки доступное?

Моя текущая попытка выглядит следующим образом :

Я бы с удовольствием использовал существующую магию.Тем не менее, HtmlHelper.GetAntiForgeryTokenAndSetCookie является приватным, и я не хочу взламывать MVC.Другой вариант - написать расширение типа

public static string PlainAntiForgeryToken(this HtmlHelper helper)
{
    // extract the actual field value from the hidden input
    return helper.AntiForgeryToken().DoSomeHackyStringActions();
}

, которое несколько взломано и оставляет большую проблему нерешенной: как проверить этот токен?Реализация проверки по умолчанию является внутренней и жестко запрограммирована на использование полей формы.Я попытался написать слегка измененный ValidateAntiForgeryTokenAttribute, но он использует AntiForgeryDataSerializer, который является частным, и я действительно не хотел копировать это тоже.

На данный момент, кажется, легче прийтис домашним решением, но это действительно дублирующий код.

Есть предложения, как сделать это умным способом?Я что-то упускаю совершенно очевидное?

1 Ответ

10 голосов
/ 28 февраля 2010

Вы можете использовать обычный помощник Html.AntiForgeryToken() для создания скрытого поля где-то на странице (не обязательно внутри формы) и включить его в запрос ajax:

var token = $('input[name=__RequestVerificationToken]').val();
$.post(
    '/SomeAction', { '__RequestVerificationToken': token }, 
    function() {
        alert('Account Deleted.');
    }
);

Чтобы проверить это на стороне сервера:

[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult SomeAction() 
{
    return View();
}

Если у вас есть несколько токенов на вашей странице, вам может потребоваться указать, какой из них включить. Поскольку существующий помощник генерирует скрытые поля с одинаковыми именами, трудно сделать хороший селектор, чтобы вы могли поместить их в промежутки:

<span id="t1"><%= Html.AntiForgeryToken() %></span>
<span id="t2"><%= Html.AntiForgeryToken() %></span>

и затем выберите соответствующий токен:

var token = $('#t1 input[name=__RequestVerificationToken]').val();
...