MVC ValidateAntiForgeryToken проблема с несколькими вкладками
Мы получали "Требуемый токен против подделки не был предоставлен или был недействительным". ошибки, и в некоторых дальнейших исследованиях мне удалось воссоздать проблему в ее простейшей форме - я либо делаю что-то совершенно неправильно, либо это ограничение системы токенов против подделки.
В любом случае, я буду признателен за несколько советов!
Пустой проект MVC 2: одна страница просмотра, один контроллер
Посмотреть:
<%--Sign in form:--%>
<% using(Html.BeginForm("SignIn", "Home", FormMethod.Post)) {%>
<%= Html.AntiForgeryToken()%>
<input type="submit" value="Sign in" />
<%}%>
контроллер:
public ActionResult Index()
{
ViewData["status"] = "Index";
return View();
}
[ValidateAntiForgeryToken]
public ActionResult SignIn()
{
ViewData["status"] = "Signed In!";
FormsAuthentication.SetAuthCookie("username", false);
return View("Index");
}
[РЕДАКТИРОВАТЬ: упрощенный пример кода]
Чтобы воссоздать исключение, откройте две не вошедшие в систему вкладки - войдите на первой вкладке, а затем войдите на второй вкладке.
Вторая вкладка всегда будет генерировать исключение для защиты от подделки, когда я предполагаю, что правильным поведением будет перенаправление на страницу входа (совместное использование сеанса / аутентификация исходной вкладки входа)
Любой совет будет принят во внимание!
Ура, Дейв
3 ответа
Реальный ответ на эту проблему заключается в том, что вы не должны использовать токен против подделки в формах входа!
Бессмысленно "подделывать" пользователя в форме входа - они не авторизованы!
Глядя на исходный код MVC 2, кажется, что скрытое поле AntiForgeryToken включает в себя сериализованный User.Identity.Name, если вы вошли в систему. В строке 69 ValidateAntiForgeryTokenAttribute
кажется, что затем проверьте ваш токен с текущим User.Identity.Name.
string currentUsername = AntiForgeryData.GetUsername(filterContext.HttpContext.User);
if (!String.Equals(formToken.Username, currentUsername, StringComparison.OrdinalIgnoreCase)) {
// error: form token is not valid for this user
// (don't care about cookie token)
throw CreateValidationException();
}
Потому что в другой вкладке вы вошли в код, приведенный выше, делает недействительным существующий токен, который не содержит User.Identity.Name.
Это можно исправить, добавив !string.IsNullOrEmpty(formToken.Username)
вокруг этой проверки, но я не знаю, вызовет ли это проблемы с безопасностью, плюс это означает наличие собственной сборки MVC 2.
Вы можете использовать ту же соль:
<% using(Html.BeginForm("SignIn", "Home", FormMethod.Post)) {%>
<%= Html.AntiForgeryToken("123")%>
<input type="submit" value="Sign in" />
<%}%>
<% using(Html.BeginForm("Protected", "Home", FormMethod.Post)) {%>
<%= Html.AntiForgeryToken("456")%>
<input type="submit" value="Do secret stuff" />
<%}%>
И в вашем контроллере:
[ValidateAntiForgeryToken(Salt = "123")]
public ActionResult SignIn()
{
ViewData["status"] = "Signed In!";
FormsAuthentication.SetAuthCookie("username", false);
return View("Index");
}
[Authorize]
[ValidateAntiForgeryToken(Salt = "456")]
public ActionResult Protected()
{
ViewData["status"] = "Authed";
return View("Index");
}
Сделайте то же самое с другим токеном, но не забудьте выбрать другую соль.