web-dev-qa-db-fra.com

Dépannage des problèmes de jeton anti-falsification

J'ai un message de formulaire qui me donne systématiquement une erreur de jeton anti-falsification.

Voici mon formulaire:

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

Voici ma méthode d'action:

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

Voici la machineKey dans web.config:

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

Et voici l'erreur que je reçois:

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

J'ai lu que changer d'utilisateur sur le HttpContext invaliderait le jeton, mais cela ne se produit pas ici. L'action HttpGet sur ma jointure renvoie simplement la vue:

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

Donc je ne suis pas sûr de ce qui se passe. J'ai cherché partout et tout semble suggérer qu'il s'agisse du changement de machineKey (cycles d'application) ou du changement d'utilisateur/de session.

Quoi d'autre pourrait se passer? Comment puis-je résoudre ce problème?

34
Jerad Rose

Après l’aide d’Adam, la source MVC a été ajoutée à mon projet et j'ai pu constater que de nombreux cas entraînaient la même erreur.

Voici la méthode utilisée pour valider le jeton anti-contrefaçon:

    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();
        }
    }

Mon problème était cette condition où il compare le nom d'utilisateur d'identité avec le nom d'utilisateur du jeton de formulaire. Dans mon cas, le nom d'utilisateur n'était pas défini (l'un était nul, l'autre était une chaîne vide). 

Bien que je doute que beaucoup d’entre eux se retrouvent dans le même scénario, d’autres espérons qu’il sera utile de voir les conditions sous-jacentes vérifiées.

18
Jerad Rose

Je ne sais pas si vous voulez dire que vous pouvez obtenir l'erreur à la demande - ou que cela se voit dans vos journaux, mais voici en tout cas un moyen de garantir une erreur de jeton antiforgery.

Attendez ...

  • Assurez-vous d'être déconnecté, puis entrez votre identifiant
  • Double-cliquez sur le bouton de connexion
  • Tu auras :

Le jeton anti-falsification fourni était destiné à l'utilisateur "", mais l'utilisateur actuel est "[email protected]".

(Pour l'instant, je vais supposer que ce message d'erreur exact a changé dans MVC4 et qu'il s'agit essentiellement du même message que vous obtenez).

Il y a beaucoup de gens là-bas qui encore double-cliquez sur tout - c'est mauvais! Je viens de comprendre ça après le réveil alors comment ça a passé les tests, je ne sais vraiment pas. Vous n'avez même pas à double-cliquer - j'ai cette erreur moi-même lorsque je clique une seconde fois si le bouton ne répond pas.

Je viens de supprimer l'attribut de validation. Mon site est toujours SSL et le risque ne me préoccupe pas excessivement. J'ai juste besoin que ça fonctionne maintenant. Une autre solution serait de désactiver le bouton avec JavaScript.

Cela peut être dupliqué sur le modèle d'installation initiale de MVC4.

30
Simon_Weaver

Vous devez empêcher la soumission de formulaires doubles . J'empêche ce type de problème à l'aide d'un code comme celui-ci:

$('#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();
});

ou 

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

AntiForgeryToken vérifie également que vos informations d'identification d'utilisateur connecté n'ont pas changé - elles sont également cryptées dans le cookie. Vous pouvez désactiver cette option en définissant AntiForgeryConfig.SuppressIdentityHeuristicChecks = true dans le fichier global.asax.cs. 

4
VahidN

Je viens tout juste de rencontrer un problème où @Html.AntiForgeryToken() était appelé deux fois, de sorte que le jeton Anti-forger était bloqué dans la charge HTTP Post.

3
Greg B

Si nécessaire, vérifiez que le formulaire est valide avant de désactiver le bouton d'envoi. 

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

2
Pažout

Êtes-vous sur un serveur ou une ferme Web? Si vous utilisez un seul serveur, commentez votre élément machineKey dans votre web.config et essayez à nouveau comme point de départ. Tout changement? De plus, pouvez-vous penser aux raisons pour lesquelles vos cookies seraient supprimés ou expireraient? Ils sont également nécessaires pour que cela fonctionne correctement. 

2

J'ai également rencontré le même problème lorsque j'ai dû migrer mon application vers une nouvelle machine. Je ne comprenais pas pourquoi cette erreur s'était soudainement manifestée, mais je pensais que cela avait quelque chose à voir avec la migration. J'ai donc commencé à enquêter sur l'enregistrement de la base de données via aspnet_reqsql. Lorsque cette erreur a été éliminée, j'ai compris qu'il devait s'agir de l'enregistrement de l'application. et bien sûr, j'ai trouvé la réponse dans un endroit similaire. Lors de mon voyage, j'ai également découvert qu'il y avait 2 façons de résoudre ce problème. 

  1. ASP.NET génère automatiquement une clé de cryptographie pour chaque application et la stocke dans la ruche de registre HKCU. Lorsque l'application est migrée ou accédée sur une batterie de serveurs, ces clés ne correspondent pas. La première méthode consiste donc à ajouter une clé d'ordinateur unique à web.config. La clé d'ordinateur peut être générée à partir de la console de gestion IIS et ajoutée à la section de votre web.config. 

    <MachineKey validationKey = "DEBE0EEF2A779A4CAAC54EA51B9ACCDED506DA2A4BEBA88FA23AD8E7399C4A8B93A006ACC1D7FEAEE56A5571B5AB6D74819CFADB522FEEB101B4D0F97F4E91" decryptionKey = validation "7B1EF067E9C561EC2F4695578295EDD5EC454F0F61DBFDDADC2900B01A53D4" = déchiffrement "SHA1" = "AES" />

  2. La deuxième méthode consiste à accorder un accès au registre HKCU pour le processus de travail via l’appPool à l’aide de AspNet_RegIIS et du commutateur -ga ou pour toutes les applications utilisant -i.

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

Quelle que soit la méthode que vous choisissez devrait résoudre ce problème, mais pour moi, le moyen le plus robuste pour les migrations et les modifications de serveur futures sera la clé unique dans le fichier web.config, en gardant à l'esprit que cela entraînerait le remplacement du registre HKCU par l'application. Ruche et maintenez votre application en cours d'exécution.

1
Graham Walker

Je viens d'avoir un problème similaire. J'ai eu:

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

Ce qui est intéressant, c’est que j’ai essayé de le déboguer et que j’ai vu le jeton aux deux endroits où je pensais le trouver dans le contrôleur.

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

En réalité, j'aurais dû regarder ici:

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

Comme Params contient plus que des champs de formulaire, il contient les chaînes QueryString, Form, Cookies et ServerVariables.

Une fois que ce hareng rouge était hors du chemin, j'ai trouvé que l'AntiForgeryToken était sous la mauvaise forme!

1
tony

Une autre chose possible à vérifier qui a causé cette erreur pour moi: j’avais deux @Html.AntiForgeryToken() dans un de mes formulaires 

Une fois que ce problème a été résolu, il est parti.

1
JensB

enregistreur d'erreur HTML n'est pas la ligne correcte.

vous devez vérifier toute la valeur de chargement dans la page n'est pas null.

0
Ali Rasouli