Problème de jeton de validation de demande de connexion

J’ai parcouru les journaux d’erreurs d’un projet de développement et j’ai trouvé l’erreur suivante (le nom a été modifié pour protéger le coupable innocent) –

Le jeton anti-falsification fourni était destiné à l’utilisateur “”, mais l’utilisateur actuel est “admin”.

Ce n’était pas un problème particulièrement difficile à reproduire.

  1. Ouvrez l’application à la page de connexion
  2. Ouvrez une seconde fenêtre ou un autre onglet du même navigateur sur le même ordinateur vers la page de connexion avant de vous connecter
  3. Connectez-vous dans la première fenêtre (ou bien la seconde n’a pas d’importance)
  4. Tentative de connexion dans la fenêtre de connexion restante

La trace de la stack est-

System.Web.Mvc.HttpAntiForgeryException (0x80004005): Le jeton anti-falsification fourni était destiné à l’utilisateur “”, mais l’utilisateur actuel est “admin”. at System.Web.Helpers.AntiXsrf.TokenValidator.ValidateTokens (HttpContextBase httpContext, identité IIdentity, AntiForgeryToken sessionToken, AntiForgeryToken fieldToken) à System.Web.Helpers.AntiXsrf.AntiForgeryWorker.Validate (HttpContextBase httpContext) à System.Web.Helpers.AntiForgery. Validate () sur System.Web.Mvc.ValidateAntiForgeryTokenAtsortingbute.OnAuthorization (AuthorizationContext filterContext) à System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters (ControllerContext controllerContext, filtres IList`1, ActionDescriptor actionDescript) à System.Web.Mvc.Async.AsyncControllerActionInvoker. c__DisplayClass25.b__1e (AsyncCallback asyncCallback, Object asyncState)

La signature de la méthode de connexion est-

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

Ceci est exactement le même que la signature de la méthode dans un projet basé sur Internet “Application ASP.NET MVC 4 Web”, qui indique que Microsoft a soit estimé que le ValidateAntiForgeryToken était nécessaire / pratique, ou simplement ajouté l’atsortingbut ici partout ailleurs.

De toute évidence, je ne peux rien faire pour résoudre le problème dans cette méthode car elle n’est pas atteinte, ValidateAntiForgeryToken est un filtre de pré-requête et bloque la requête avant qu’elle n’atteigne le contrôleur.

Je pourrais vérifier si l’utilisateur est authentifié via Ajax avant de soumettre le formulaire et tenter de le redirect si tel est le cas, ou simplement supprimer l’atsortingbut.

La question est la suivante: si je comprends bien, le jeton est conçu pour empêcher les demandes provenant d’un autre site (CSRF) lorsque l’utilisateur est déjà authentifié sur votre site . Il est donc difficile de le supprimer d’un formulaire par définition. par des utilisateurs non authentifiés ?

Il est probable que l’atsortingbut dans cette instance est conçu pour atténuer les acteurs malveillants fournissant de faux formulaires de connexion pour votre application (même si au moment où l’exception est lancée, il est probable que l’utilisateur a déjà saisi ses informations, mais cela pourrait les alerter) est faux). Sinon, l’envoi de références incorrectes au formulaire à partir d’un site externe entraînera certainement le même résultat que sur le site lui-même? Je ne compte pas sur la validation / assainissement du client pour nettoyer les entrées potentiellement dangereuses.

D’autres développeurs ont-ils rencontré ce problème (ou avons-nous des utilisateurs exceptionnellement créatifs) et si oui, comment l’avez-vous résolu / atténué?

Mise à jour: ce problème existe toujours dans MVC5, à dessein intentionnel, maintenant avec le message d’erreur “Le jeton anti-contrefaçon fourni était destiné à un utilisateur différent basé sur les revendications que l’utilisateur actuel.” lors de l’utilisation du modèle par défaut et des fournisseurs d’identité. Il y a une question pertinente et une réponse intéressante de la part de l’évangéliste Microsoft Developer Adam et de l’auteur de PluralSight de Troy, Adam Tuliper, sur Anti to Few token sur la page de connexion .

Je viens de tester ce pattern sur ASafaWeb avec le même résultat (il utilise la même implémentation par défaut). Voici ce que je crois se passe

  1. Les deux formulaires de connexion se chargent avec le même cookie __RequestVerificationToken (le même que celui défini dans le même DOM) et le même champ masqué __RequestVerificationToken. Ces jetons sont indexés à un utilisateur anonyme.
  2. Formulaire de connexion Un posts avec les jetons ci-dessus, valide puis retourne un cookie d’authentification qui se trouve maintenant dans le navigateur DOM
  3. Le formulaire de connexion B publie également avec les jetons ci-dessus, mais maintenant, il affiche également le jeu de cookies d’authentification du formulaire de connexion A.

Le problème est que le jeton n’est pas validé à l’étape 3 car il est atsortingbué à un utilisateur anonyme, mais il est transmis dans la demande par un utilisateur authentifié. C’est pourquoi vous voyez l’erreur: le jeton anti-falsification fourni était destiné à l’utilisateur “”, mais l’utilisateur actuel est “admin”.

Vous ne rencontrez ce problème que parce que le formulaire B chargé avant le formulaire A est posté, par conséquent le formulaire B s’attend à être publié par un utilisateur anonyme.

Est-ce un problème de le supprimer d’un formulaire qui, par définition, sera utilisé par des utilisateurs non authentifiés?

Le risque sous-jacent prédominant contre lequel les jetons anti-contrefaçon protègent est le CSRF qui profite généralement des utilisateurs authentifiés du fait que toute requête de leur navigateur pouvant être trompée sera automatiquement accompagnée d’un cookie d’authentification. au nom de Ce risque n’existe pas sur le formulaire de connexion, car l’utilisateur n’est généralement pas authentifié et le pire cas de CSRF ici est qu’une connexion est falsifiée puis échoue; vous ne transférez pas exactement de l’argent au nom de l’utilisateur!

Le jeton anti-contrefaçon présente cependant d’autres avantages: par exemple, il empêche les attaques par force brute qui exécutent effectivement la méthode et frappent la firebase database. Vous devez décider si vous êtes moins inquiet à ce sujet et plus préoccupé par le scénario que vous rencontrez dans votre question. Soit cela, soit vous devez vous rendre quelque part dans le pipeline de demandes et agir si un cookie d’authentification est déjà présent dans la demande avant que la validation anti-falsification ait lieu.

Franchement cependant, je ne suis pas sûr de voir le problème; Pour reproduire ce problème, l’utilisateur doit ouvrir plusieurs formulaires de connexion en même temps, puis essayer de se connecter à chacun d’eux. Cela va-t-il vraiment se produire? Et quand cela se produit, est-il vraiment important que la deuxième connexion renvoie une page d’erreur personnalisée (ce que vous feriez bien sûr en production)? IMHO, laissez le comportement par défaut.

Le code de validation qui s’exécute sur un AntiForgeryToken vérifie également que les informations d’identification de l’utilisateur connecté n’ont pas changé. Celles-ci sont également cryptées dans le cookie. Cela signifie que si vous vous êtes connecté ou déconnecté dans une fenêtre contextuelle ou un autre onglet du navigateur, votre soumission de formulaire échouera avec l’exception suivante:

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

Vous pouvez désactiver cette option en mettant AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; dans la méthode Application_Start dans le fichier Global.asax .

Lorsqu’un AntiForgeryToken ne valide pas votre site Web, il génère une exception de type System.Web.Mvc.HttpAntiForgeryException . Vous pouvez rendre cela plus facile en donnant au moins à l’utilisateur une page plus informative ciblée sur ces exceptions en interceptant l’exception 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); } } 

Ok, corrigez-moi si ma supposition est incorrecte.

Lorsque cette exception est lancée, vous préférez laisser l’utilisateur continuer tout en affichant un message / avertissement approprié? Parce que lorsque cette exception est lancée, nous pouvons déjà savoir si l’utilisateur actuel est authentifié – nous avons access à la demande.

Alors, pourquoi cela ne serait-il pas acceptable?

 [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public ActionResult Login(LoginModel model, ssortingng returnUrl) { ... } ///  /// Handle HttpAntiForgeryException and redirect if user is already authenticated ///  ///  ///  /// See: http://stackoverflow.com/questions/19096723/login-request-validation-token-issue ///  protected override void OnException(ExceptionContext filterContext) { base.OnException(filterContext); var action = filterContext.RequestContext.RouteData.Values["action"] as ssortingng; var controller = filterContext.RequestContext.RouteData.Values["controller"] as ssortingng; 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"); } } 

Est-ce que je manque quelque chose de évident ici? Je vais supprimer cette réponse si elle ne comporte pas d’implication.

J’ai eu le même problème, je l’ai résolu en ajoutant machineKey à system.web>

  

Voici un site qui génère des clés Machnie uniques http://www.developerfusion.com/tools/generatemachinekey/

Fonctionne très bien, je comprends que Anti Forgery peut ne pas être nécessaire dans une page de connexion, mais si quelqu’un est déterminé à pirater votre site, il est rassurant de savoir que [ValidateAntiForgeryToken] est là pour les contrecarrer.