RequestVerificationToken не соответствует - PullRequest
34 голосов
/ 14 октября 2011

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

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

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

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

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

Иэто возвращенный Cookie:

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

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

__RequestVerificationToken:QK8P7rjyZE6Vm5seY7Fr704YCOoFGdTIMzl1W7R0ZFpXSMjGKLG2T05DfFSYTxvtQCEx7DDT69DGsDB2%2BZXFHY8oAjiKz0gw8BhDFywgmfIpoXnGpj7fONNzIIfvbrDrE9WJsMu6Io%2F0bDLM5WfKs0zktiNjyOWpfYrmnfINYmjW8NLOZFoz74xTcgTptAld

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

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

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

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

С уважением.

Ответы [ 3 ]

77 голосов
/ 24 октября 2011

В последнее время у меня было и решено несколько проблем с 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 для шифрования токенов и файлов cookie. Кажется излишним.

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

4 голосов
/ 21 октября 2011

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

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

2 голосов
/ 01 августа 2013

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

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

Если вы зададите тип контента «application / json», токен перейдет в свойство «headers» ajax, как описано в haack.

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

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

...