RequestVerificationToken не соответствует

У меня проблема с механизмом анти CRSF MVC. Файл cookie и введенные данные не совпадают. Я получаю сообщение об ошибке каждый раз, только на одной конкретной странице. В остальной части приложения это работает хорошо.

Сервер возвращается HTTP 500 Internal Server Error и я вижу в журнале это исключение:

[System.Web.Mvc.HttpAntiForgeryException]: {"Требуемый токен защиты от подделки не был предоставлен или был недействительным."}

Это скрытый ввод, который генерирует сервер:

<input name="__RequestVerificationToken" type="hidden" value="QK8P7rjyZE6Vm5seY7Fr704YCOoFGdTIMzl1W7R0ZFpXSMjGKLG2T05DfFSYTxvtQCEx7DDT69DGsDB2+ZXFHY8oAjiKz0gw8BhDFywgmfIpoXnGpj7fONNzIIfvbrDrE9WJsMu6Io/0bDLM5WfKs0zktiNjyOWpfYrmnfINYmjW8NLOZFoz74xTcgTptAld">

И это печенье возвращается:

Set-Cookie:__RequestVerificationToken_L2VGbG93=skmTAVI8HCbfxDS+xhioIMIISL3UOBI7qJM1JbHjTtAqKl4W70pDUcTKMm0p3R3mrHDziE8vXw0C0OO4HArzWO1/e6py+v/cFdbe9maFgjl4jMiZ9Wc4YIhC6+IUXkk6yqJDJ8dCIr8qtGaYcD9IX+m7/SlVhu521KQSWJYRcaY=; path=/; HttpOnly

Когда я проверяю, что сервер отправляет, cookie-файл точно такой же, но полезная нагрузка имеет другую кодировку:

__RequestVerificationToken:QK8P7rjyZE6Vm5seY7Fr704YCOoFGdTIMzl1W7R0ZFpXSMjGKLG2T05DfFSYTxvtQCEx7DDT69DGsDB2%2BZXFHY8oAjiKz0gw8BhDFywgmfIpoXnGpj7fONNzIIfvbrDrE9WJsMu6Io%2F0bDLM5WfKs0zktiNjyOWpfYrmnfINYmjW8NLOZFoz74xTcgTptAld

Различия в двух символах, которые выглядят закодированными:

    /    ->   %2F  
    +    ->   %2B

Это единственные различия, которые я могу найти между скрытым полем ввода и полезной нагрузкой поста.

В чем может быть проблема, которая вызывает это ValidateAntiForgeryToken не в состоянии проверить токен?

С уважением.

3 ответа

Решение

Я имел и решил несколько проблем с ValidateAntiForgeryToken В последнее время я поделюсь с вами своими выводами.

Соль: Поскольку вы упоминаете, что это происходит только на одной странице, я думаю, что вы используете разные salt значения в ваших звонках Html.AntiForgeryToken(salt) а также ValidateAntiForgeryToken(salt) звонки.

AJAX: как уже сказал другой ответ, использование AJAX может потребовать дополнительной работы, чтобы убедиться, что токен включен в POST. Вот мое любимое простое, автоматическое решение для добавления токена ко всем запросам AJAX POST.
В своем вопросе вы утверждаете, что подтвердили, что токен отправляется. Вы убедились, что отправляете токен только один раз? Я обнаружил, что мой AJAX-вызов дважды отправлял токен, который объединял значения и вызывал его сбой.

Ключ компьютера и файлы cookie: эта проблема уродлива, ее легко обнаружить (вызывает исключения), но она не очень понятна. Файлы cookie и токены проверки кодируются и декодируются с использованием уникального "машинного ключа". Это означает, что если у вас есть ферма серверов или вы изменили свой сервер, ваш файл cookie больше не будет действительным. Закрытие вашего браузера решает проблему (потому что cookie - это cookie сессии). Однако некоторые люди оставляют свои окна браузера открытыми в фоновом режиме надолго!
Решением является установка "машинного ключа" в вашем конфигурационном файле. Это скажет MVC использовать один и тот же ключ на всех серверах, гарантируя, что cookie будет расшифрован везде.

Ошибки кодирования: используя утилиту тестирования jMeter, мы попытались выполнить нагрузочное тестирование наших страниц, только чтобы выяснить, что в ней была ошибка, из-за которой у нашего токена было 2 дополнительных " вокруг значения.
Решение состоит в том, чтобы снизить доверие к своим инструментам! Проверьте в браузере, и если это сработает, создайте тест, который извлекает значения токена и cookie, и установите точку останова для проверки результатов.

Если ни одна из этих вещей не работает для вас, то я рекомендую взглянуть на исходный код MVC дляValidateAntiForgeryTokenAttributeконкретно OnAuthorization метод. Это поможет вам увидеть различные этапы, на которых валидация может быть неудачной. Вы можете даже проверить свою ошибку Exception.StackTrace определить, какая часть выходит из строя.

Как примечание, мне очень не нравится реализация ValidateAntiForgeryToken в MVC, потому что:

  • Существует около 5 шагов проверки, которые могут завершиться неудачей, но есть только одно общее сообщение об ошибке.
  • Класс запечатан, поэтому он не может быть расширен дополнительными функциями.
  • Метод шифрования странный - он инициализирует Page и создает искусственный ViewState шифровать токены и куки. Кажется излишним.

Итак, я взял исходный код и создал свой собственный специализированный подкласс, который также оказался очень полезным при отладке его проблем, потому что я мог устанавливать контрольные точки для методов проверки, и было действительно легко определить, какой этап проверки не удался,

Если это отправляется как Ajax-запрос, то текущая настройка фреймворка не собирается для этого естественным образом.

К счастью, Фил Хаак написал хороший пост в блоге о работе с CSRF и Ajax -> Предотвращение CSRF с помощью Ajax, в котором подробно объясняется, как использовать существующую среду и изменить ее для работы с Ajax/Json.

Из моих недавних открытий...

Если вы задали тип контента как "application/x-www-form-urlencoded" в запросе ajax, то вы должны поместить AFRT в данные

Если вы установите тип содержимого "application/json", то токен перейдет в свойство "headers" ajax, как описано в haack.

На сервере, если вы проверяете токен типа формы, тогда можно использовать vanilla AntiForgeryRequestTokenAttribute, но если вы хотите проверить токены, отправленные в заголовке, вам нужно вызвать AntiForgeryToken.OnAuthorize... или что-то еще, передав токен из cookie (http-контекст).

Это не легко, но если бы все это делали:)

Другие вопросы по тегам