Ошибка маркера проверки входного запроса

Я просматриваю журналы ошибок проекта разработки и обнаружил следующую ошибку (имя изменено для защиты виновного невинно) -

Предоставленный токен анти-подделки предназначен для пользователя ", но текущий пользователь" admin".

Это не было особенно сложной проблемой для воспроизведения -

  • Откройте приложение на странице входа
  • Откройте второе окно или вкладку того же браузера на том же компьютере на странице входа в систему перед входом в систему
  • Войдите в первое окно (или, действительно, второе, порядок не имеет значения)
  • Попытка входа в оставшееся окно входа в систему

Трассировка стека -

System.Web.Mvc.HttpAntiForgeryException(0x80004005): предоставленный токен анти-подделки предназначался для пользователя ", но текущий пользователь" Админы". в System.Web.Helpers.AntiXsrf.TokenValidator.ValidateTokens(HttpContextBase httpContext, идентификатор IIdentity, AntiForgeryToken sessionToken, Поле AntiForgeryTokenToken) при System.Web.Helpers.AntiXsrf.AntiForgeryWorker.Validate(HttpContextBase httpContext) в System.Web.Helpers.AntiForgery.Validate() at System.Web.Mvc.ValidateAntiForgeryTokenAttribute.OnAuthorization(AuthorizationContext filterContext) в System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controlContext, IList`1, ActionDescriptor actionDescriptor) в System.Web.Mvc.Async.AsyncControllerActionInvoker <. > C__DisplayClass25.b__1e (AsyncCallback asyncCallback, Object asyncState)

Подпись метода входа -

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
...
}

Это точно так же, как подпись для метода в веб-проекте "ASP.NET MVC 4 Web Application", который указывает, что Microsoft либо почувствовала, что ValidateAntiForgeryToken была необходима/передовая практика, либо просто добавила атрибут здесь, потому что он использовался повсюду.

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

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

Вопрос в том, что я понимаю, что маркер - это дизайн для предотвращения запросов с другого сайта (CSRF), когда пользователь уже прошел аутентификацию против вашего сайта, поэтому на этой основе это проблема удаления его из формы которые по определению будут использоваться неавторизованными пользователями?

Предположительно, атрибут в этом случае предназначен для смягчения злонамеренных участников, предоставляющих поддельные формы входа для вашего приложения (хотя к тому времени, когда исключение выбрасывается, предположительно, пользователь уже ввел свои данные, которые будут записаны, но может предупредить их, что-то не так). В противном случае представление неправильных учетных данных в форму с внешнего сайта приведет к точно таким же результатам, что и на самом сайте? Я не полагаюсь на проверку/санитарию клиента для очистки потенциально опасного ввода.

Если другие разработчики сталкиваются с этой проблемой (или у нас необычно творческие пользователи), и если да, то как вы ее разрешили/смягчили?

Обновление: Эта проблема все еще существует в MVC5, полностью преднамеренно, теперь с сообщением об ошибке "Предоставленный токен анти-подделки предназначен для другого пользователя, основанного на требованиях, чем у текущего пользователя". при использовании шаблонов по умолчанию и поставщиков удостоверений. Существует важный вопрос и интересный ответ от разработчика Microsoft Developer Evangelist и Troy, написанного автором PluralSight Адама Тульпера, в токене антивируса на странице входа в систему, который рекомендует просто удалить токен.

Ответ 1

Я только что проверил этот шаблон на ASafaWeb с тем же результатом (он использует ту же самую реализацию по умолчанию). Вот что я считаю происходящим

  • Обе формы входа в систему загружаются с тем же файлом cookie __RequestVerificationToken (он точно такой же, как и в том же DOM) и тем же скрытым полем __RequestVerificationToken. Эти маркеры привязаны к анонимному пользователю.
  • Форма входа в систему. Сообщения с указанными маркерами, проверяющие их, затем возвращает файл cookie auth, который теперь находится в браузере DOM
  • Форма входа в форму B также с указанными маркерами, но теперь она также отправляет с помощью файла cookie auth из формы входа A.

Проблема заключается в том, что токен не проверяется на шаге 3, поскольку он привязан к анонимному пользователю, но он передается в запросе аутентифицированным пользователем. Вот почему вы видите ошибку: Предоставленный токен анти-подделки предназначен для пользователя ", но текущий пользователь" admin"

У вас есть только эта проблема, потому что форма B загружена до опубликованной формы A, поэтому форма B ожидает анонимного пользователя.

Является ли проблема удалить его из формы, которая по определению будет использоваться неаутентифицированными пользователями?

Преобладающим основным риском, который защищают от подделки подделки, является CSRF, который обычно использует преимущества аутентифицированных пользователей из-за того, что любые запросы, которые их браузер может обмануть при выдаче, будут автоматически сопровождаться файлом auth, поэтому действие будет выполняемые от их имени. Этот риск не существует в форме входа в систему, потому что обычно пользователь не аутентифицирован, а худший случай CSRF заключается в том, что логин подделан, а затем сбой; вы точно не переводите деньги от имени пользователя!

Существуют и другие преимущества токена анти-подделки: например, он предотвращает атаку грубой силы, фактически выполняющую этот метод и попадающий в БД. Вам нужно решить, если вы меньше беспокоитесь об этом и больше беспокоитесь о сценарии, с которым вы сталкиваетесь в своем вопросе. Либо это, либо вам нужно спуститься в конвейер запроса где-нибудь и предпринять меры, если файл auth cookie уже присутствует в запросе до того, как произойдет проверка анти-подделки.

Честно говоря, я не уверен, что вижу проблему; чтобы воспроизвести эту проблему, пользователь должен одновременно открыть несколько форм входа в систему, а затем попытаться войти в каждый подряд - действительно ли это произойдет, чтобы беспокоиться? И когда это происходит, действительно ли имеет значение, что второй логин возвращает страницу пользовательских ошибок (что, конечно, вы сделали бы на производстве)? IMHO, оставьте поведение по умолчанию.

Ответ 2

Код проверки, который работает с AntiForgeryToken, также проверяет ваши зарегистрированные учетные данные пользователя, которые были изменены - они также зашифрованы в файле cookie. Это означает, что если вы вошли в систему или вне ее во всплывающей или другой вкладке браузера, ваша подача формы завершится неудачей со следующим исключением:

System.Web.Mvc.HttpAntiForgeryException (0x80004005):
The provided anti-forgery token was meant for user "", but the current user is "SomeOne".

Вы можете отключить это, поместив AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; в Application_Start внутри файла Global.asax.

Когда AntiForgeryToken не проверяет ваш сайт, вы выбрали исключение типа System.Web.Mvc.HttpAntiForgeryException. Вы можете сделать это немного легче, по крайней мере, предоставив пользователю более информативную страницу, нацеленную на эти исключения, поймав HttpAntiForgeryException.

private void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();

if (ex is HttpAntiForgeryException)
  {
    Response.Clear();
    Server.ClearError(); //make sure you log the exception first
    Response.Redirect("/error/antiforgery", true);
  }
}

Ответ 3

Хорошо, пожалуйста, исправьте меня, если мое предположение неверно.

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

Итак, почему это не приемлемо?

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
...
}

/// <summary>
/// Handle HttpAntiForgeryException and redirect if user is already authenticated
/// </summary>
/// <param name="filterContext"></param>
/// <remarks>
/// See: http://stackoverflow.com/questions/19096723/login-request-validation-token-issue
/// </remarks>
protected override void OnException(ExceptionContext filterContext)
{
    base.OnException(filterContext);

    var action = filterContext.RequestContext.RouteData.Values["action"] as string;
    var controller = filterContext.RequestContext.RouteData.Values["controller"] as string;

    if ((filterContext.Exception is HttpAntiForgeryException) &&
        action == "Login" &&
        controller == "MyController" &&
        filterContext.RequestContext.HttpContext.User != null &&
        filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated)
    {
        LogManager.GetCurrentClassLogger().Warn(
            "Handled AntiForgery exception because user is already Authenticated: " +
                filterContext.Exception.Message, filterContext.Exception);

        filterContext.ExceptionHandled = true;

        // redirect/show error/whatever?
        filterContext.Result = new RedirectResult("/warning");
    }
}

Я пропустил что-то очевидное здесь? Я удалю этот ответ, если у меня есть какая-то импликация, которую я не вижу.

Ответ 4

У меня была такая же проблема, я решил ее, добавив machineKey в   system.web >

<machineKey validationKey="your machine key numbers" 
decryptionKey="Your description key nuumbers" validation="SHA1" decryption="AES" />

Здесь сайт, который генерирует уникальные ключи Machnie   http://www.developerfusion.com/tools/generatemachinekey/

Отлично работает, я понимаю, что Anti Forgery может не понадобиться на странице входа в систему, но если кто-то решил взломать ваш сайт, вам приятно узнать, что [ValidateAntiForgeryToken] существует, чтобы помешать им.