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

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

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

[системы.Сеть.В 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

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

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

С уважением.

3 ответов


у меня было и решено несколько проблем с ValidateAntiForgeryToken в последнее время, поэтому я поделюсь с вами моими результатами.

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

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

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

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

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

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

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

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


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

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


из моих последних находок ...

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

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

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

Это не так просто, но если бы это было все будут делать это:)