J'ai parcouru les journaux d'erreurs d'un projet de développement et j'ai trouvé l'erreur suivante (nom 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 une question particulièrement difficile à reproduire.
La trace de la pile est-
System.Web.Mvc.HttpAntiForgeryException (0x80004005): Le jeton anti-falsification fourni était destiné à l'utilisateur "", mais l'utilisateur actuel est "admin". à la suite de la suite Valider () sur System.Web.Mvc.ValidateAn <> 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, string returnUrl)
{
...
}
Cela correspond exactement à la signature de la méthode dans un projet basé sur un modèle "Application Web ASP.NET MVC 4" Internet, qui indique que Microsoft a estimé que ValidateAntiForgeryToken était nécessaire/meilleure pratique, ou simplement ajouté l'attribut ici, car il était utilisé. partout ailleurs.
Évidemment, je ne peux rien faire pour gérer le problème dans car cette méthode n’est pas atteinte, ValidateAntiForgeryToken est un filtre de pré-demande et bloque la demande 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 rediriger vers eux si c'est le cas, ou simplement supprimer l'attribut.
La question est la suivante: je comprends que 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 donc sur cette base est-ce un problème de le supprimer d'un formulaire qui, par définition, sera utilisé par des utilisateurs non authentifiés ?
Il est probable que l'attribut dans cette instance est conçu pour atténuer les actes d'acteurs malveillants fournissant de faux formulaires de connexion pour votre application (bien que, au moment où l'exception est levée, l'utilisateur a probablement déjà entré ses détails qui auront déjà été enregistrés - mais cela pourrait les alerter est faux). Sinon, si vous envoyez des identifiants incorrects au formulaire à partir d'un site externe, vous obtiendrez exactement le même résultat que sur le site lui-même. Je ne compte pas sur la validation/l'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 inhabituellement créatifs) et si oui, comment l'avez-vous résolu/atténué?
Mise à jour: Ce problème persiste toujours dans MVC5, avec le message d'erreur suivant: "Le jeton anti-falsification fourni était destiné à une autre base de revendications. utilisateur que l'utilisateur actuel ". lors de l'utilisation de modèles par défaut et de fournisseurs d'identité. Il existe une question pertinente et une réponse intéressante de Adam Developer, développeur de Microsoft Developer Evangelist et de Troy, auteur de PluralSight, à l'adresse Jeton anti-contrefaçon sur la page de connexion qui recommande de supprimer simplement le jeton.
Je viens de tester ce modèle sur ASafaWeb avec le même résultat (il utilise la même implémentation par défaut). Voici ce que je crois qui se passe
Le problème est que le jeton n'est pas validé à l'étape 3, car il est attribué à un utilisateur anonyme, mais il est transmis à 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 rencontrez ce problème uniquement parce que le formulaire B est chargé avant le formulaire A, ce qui signifie que le formulaire B devrait être envoyé 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 que les jetons anti-contrefaçon protègent est le CSRF qui généralement tire parti des utilisateurs authentifiés car toutes les demandes que leur navigateur peut être amené à émettre seront automatiquement accompagnées d'une autorisation. cookie donc l'action sera effectuée en leur nom. Ce risque n'existe pas sur le formulaire de connexion car l'utilisateur n'est généralement pas authentifié et le pire des cas CSRF est qu'une connexion est falsifiée puis échoue. vous ne transférez pas exactement de l'argent pour le compte de l'utilisateur!
Toutefois, le jeton anti-contrefaçon présente d’autres avantages: il empêche par exemple les attaques par force brute d’exécuter la méthode et de toucher la base de données. Vous devez décider si vous êtes moins inquiet à ce sujet et plus inquiet du scénario que vous rencontrez dans votre question. Soit cela, soit vous devez aller quelque part dans le pipeline de demandes et prendre des mesures si un cookie d'authentification est déjà présent dans la demande avant la validation anti-falsification.
Franchement cependant, je ne suis pas sûr de voir le problème; Pour reproduire ce problème, l'utilisateur doit avoir plusieurs formulaires de connexion ouverts en même temps, puis essayer de se connecter successivement. Est-ce que cela va vraiment arriver assez de soucis? Et quand cela se produit, est-il vraiment important que la deuxième connexion retourne une page d'erreur personnalisée (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 vos informations d’identité d’utilisateur connecté n’ont pas changé - elles sont également cryptées dans le cookie. Cela signifie que si vous êtes connecté ou déconnecté dans une fenêtre contextuelle ou un autre onglet de navigateur, la soumission de votre 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 Application_Start méthode à l'intérieur du fichier Global.asax .
Lorsqu'un AntiForgeryToken ne valide pas votre site Web, une exception de type est générée (== --- ==) System.Web.Mvc.HttpAntiForgeryException . Vous pouvez rendre cela un peu 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 mon hypothèse est incorrecte.
Lorsque cette exception est levée, vous préférez laisser l’utilisateur continuer tout en affichant peut-être un message/avertissement pertinent? Parce que lorsque cette exception est levée, nous pouvons déjà savoir si l'utilisateur actuel est authentifié - nous avons accès à la requête.
Alors, pourquoi cela ne serait-il pas acceptable?
[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");
}
}
Est-ce que je manque quelque chose d'évident ici? Je vais supprimer cette réponse si cela implique quelque chose que je ne vois pas.