Устранение проблем с фальсификацией токенов

У меня есть форма сообщения, которое постоянно выдает мне ошибку токена против подделки.

Вот моя форма:

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.EditorFor(m => m.Email)
    @Html.EditorFor(m => m.Birthday)
    <p>
        <input type="submit" id="Go" value="Go" />
    </p>
}

Вот мой метод действия:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Join(JoinViewModel model)
{
    //a bunch of stuff here but it doesn't matter because it's not making it here
}

Вот ключ машины в web.config:

<system.web>
  <machineKey validationKey="mykey" decryptionKey="myotherkey" validation="SHA1" decryption="AES" />
</system.web>

И вот ошибка, которую я получаю:

A required anti-forgery token was not supplied or was invalid.

Я читал, что изменение пользователей в HttpContext сделает токен недействительным, но здесь этого не происходит. HttpGet в моем действии Join просто возвращает представление:

[HttpGet]
public ActionResult Join()
{
    return this.View();
}

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

Что еще может происходить? Как я могу устранить это?

12 ответов

Решение

После помощи Адама я добавил источник MVC в свой проект и смог увидеть, что есть много случаев, приводящих к одной и той же ошибке.

Вот метод, используемый для проверки токена защиты от подделки:

    public void Validate(HttpContextBase context, string salt) {
        Debug.Assert(context != null);

        string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null);
        string cookieName = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath);

        HttpCookie cookie = context.Request.Cookies[cookieName];
        if (cookie == null || String.IsNullOrEmpty(cookie.Value)) {
            // error: cookie token is missing
            throw CreateValidationException();
        }
        AntiForgeryData cookieToken = Serializer.Deserialize(cookie.Value);

        string formValue = context.Request.Form[fieldName];
        if (String.IsNullOrEmpty(formValue)) {
            // error: form token is missing
            throw CreateValidationException();
        }
        AntiForgeryData formToken = Serializer.Deserialize(formValue);

        if (!String.Equals(cookieToken.Value, formToken.Value, StringComparison.Ordinal)) {
            // error: form token does not match cookie token
            throw CreateValidationException();
        }

        string currentUsername = AntiForgeryData.GetUsername(context.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();
        }

        if (!String.Equals(salt ?? String.Empty, formToken.Salt, StringComparison.Ordinal)) {
            // error: custom validation failed
            throw CreateValidationException();
        }
    }

Моя проблема заключалась в том условии, что он сравнивает имя пользователя Identity с именем пользователя токена формы. В моем случае у меня не было задано имя пользователя (одно было пустым, другое - пустой строкой).

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

Я не знаю, имеете ли вы в виду, что вы можете получить ошибку по требованию - или вы видите ее в своих журналах, но в любом случае есть способ гарантировать ошибку токена защиты от подделки.

Ждать его...

  • Убедитесь, что вы вышли из системы, затем введите свой логин
  • Двойной щелчок по кнопке входа
  • Ты получишь:

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

(На данный момент я собираюсь предположить, что это точное сообщение об ошибке изменилось в MVC4 и что это по сути то же самое сообщение, которое вы получаете).

Есть много людей, которые все еще дважды щелкают по всему - это плохо! Я только что понял это после того, как только проснулся, так как я прошел через тестирование, я действительно не знаю. Вам даже не нужно дважды щелкать мышью - я сам получаю эту ошибку, когда нажимаю второй раз, если кнопка не отвечает.

Я только что удалил атрибут проверки. Мой сайт всегда SSL, и я не слишком обеспокоен риском. Мне просто нужно, чтобы это работало прямо сейчас. Другим решением будет отключение кнопки с помощью JavaScript.

Это может быть продублировано в шаблоне начальной установки MVC4.

AntiForgeryToken также проверяет, что ваши учетные данные вошедшего в систему пользователя не изменились - они также зашифрованы в файле cookie. Вы можете отключить это, установив AntiForgeryConfig.SuppressIdentityHeuristicChecks = true в файле global.asax.cs.

Вы должны предотвратить двойную форму подачи. Я предотвращаю этот тип проблемы, используя код, подобный этому:

$('#loginForm').on('submit',function(e){
    var $form = $(this);

    if (!$form.data('submitted') && $form.valid()) {
      // mark it so that the next submit can be ignored
      $form.data('submitted', true);
      return;
    }

    // form is invalid or previously submitted - skip submit
    e.preventDefault();
});

или же

$('#loginForm').submit(function () {
    $(this).find(':submit').attr('disabled', 'disabled'); 
});

Вы на одном сервере или веб-ферме? Если это один сервер, закомментируйте элемент machineKey в файле web.config и попробуйте снова в качестве базовой отправной точки. Любое изменение? Кроме того - можете ли вы подумать о каких-либо причинах, по которым ваши куки-файлы будут очищены или истекают - они необходимы для того, чтобы это работало также правильно

Я только что столкнулся с проблемой, когда @Html.AntiForgeryToken() вызывался дважды, поэтому токен Anti-forger был испорчен в полезной нагрузке HTTP Post.

Необходимо отключить проверку формы, прежде чем отключить кнопку отправки.

<script type="text/javascript">
//prevent double form submission
$('form', '#loginForm').submit(function () {
    if ($(this).valid()) {
        $(this).find(':submit').attr('disabled', 'disabled');
    }
});

У меня также была такая же проблема, когда мне приходилось переносить приложение на новый компьютер. Я не мог понять, почему эта ошибка внезапно проявилась, но я был уверен, что это как-то связано с миграцией, поэтому начал исследовать регистрацию базы данных через aspnet_reqsql, когда это было устранено, я понял, что это должно быть связано с регистрацией приложения. и, конечно же, я нашел ответ в аналогичном месте. Я также в своем путешествии обнаружил, что есть 2 способа решить эту проблему.

  1. ASP.NET автоматически генерирует ключ криптографии для каждого приложения и сохраняет ключ в кусте реестра HKCU. При переносе или обращении к приложению на ферме серверов эти ключи не совпадают, поэтому первый способ заключается в добавлении уникального ключа компьютера в файл web.config. Ключ компьютера можно сгенерировать из консоли управления IIS и добавить в раздел вашего web.config.

  2. Второй способ - предоставить доступ к реестру HKCU для рабочего процесса через appPool с помощью AspNet_RegIIS и ключ -ga или для всех приложений, использующих -i

aspnet_regiis -ga "IIS APPPOOL \ app-pool-name"

Какой бы метод вы ни выбрали, следует решить эту проблему, но, на мой взгляд, наиболее надежным способом будущих миграций и изменений на сервере будет уникальный ключ в файле web.config, учитывая, что это приведет к тому, что приложение переопределит реестр HKCU. улей и держать вас приложение работает.

Еще одна возможная вещь, чтобы проверить, что вызвало эту ошибку для меня: у меня было два @Html.AntiForgeryToken() в одной из моих форм.

Как только это было устранено, проблема ушла.

У меня просто была похожая проблема. Я получил:

The required anti-forgery form field "__RequestVerificationToken" is not present. 

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

var formField = HttpContext.Request.Params["__RequestVerificationToken"];
var cookie = System.Web.HttpContext.Current.Request.Cookies["__RequestVerificationToken"].Value;

На самом деле я должен был посмотреть здесь:

var formField = HttpContext.Request.Form["__RequestVerificationToken"];

Поскольку Params содержит больше, чем просто поля формы, он содержит QueryString, Form, Cookies и ServerVariables.

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

Также попал вA required anti-forgery token was not supplied or was invalid.сообщение сегодня.

Проблема была связана сhttpsпротивhttpи фактическая основная причина заключалась в том, что я не осознавал, что запускал API-приложение, используя конфигурацию только с http, а веб-спа - с использованием https.

Надеюсь, это поможет кому-то не тратить 4 часа жизни из-за ошибки пользователя.

HTML-журнал ошибок не является правильной строкой.

Вы должны проверить все значения загрузки на странице не является нулевым.

Другие вопросы по тегам