Подтвердить что ты не робот

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

У меня проблема с механизмом анти 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 при проверке токена?

С уважением.

4b9b3361

Ответ 1

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

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

Ответ 2

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

Luckly Phil Haak написал хороший пост в блоге по работе с CSRF и Ajax → Предотвращение CSRF с помощью Ajax, в котором подробно рассказывается о том, как использовать существующую структуру и изменить ее для работы в Ajax/Json.

Ответ 3

Из моих недавних результатов...

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

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

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

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