Je veux protéger nos actions de connexion par l'attribut AntiforgeryToken - Je sais pourquoi l'exception du sujet se produit, mais je n'arrive pas à trouver une bonne solution pour cela.
Disons que nous avons les situations suivantes:
Il est 8 h 00, les utilisateurs de l'application viennent travailler, ils s'assoient et commencent le processus de connexion - en ce moment, il est très possible que certains utilisateurs obtiendront la même chose ValidationToken. Après la première connexion, tous les autres verront l'exception ci-dessus (ou un autre écran d'exception personnalisé) lorsqu'ils tenteront de se connecter.
Un utilisateur s'est connecté, puis a accidentellement appuyé sur le bouton "retour" et a tenté de se reconnecter - bien que cela soit plus improbable, cela peut arriver, et je ne veux pas que les utilisateurs voient des exceptions lorsqu'il le fait .
La question est donc simple - comment éviter les situations ci-dessus, ou comment les gérer pour que les utilisateurs ne remarquent rien. J'ai essayé ce qui suit:
En ce moment, je pensais à valider manuellement le jeton dans le corps de l'action, intercepter l'erreur et vérifier si une tentative a été faite par un utilisateur anonyme:
public ActionResult SomeAction()
{
try
{
AntiForgery.Validate();
}
catch(HttpAntiForgeryException ex)
{
if(String.IsNullOrEmpty(HttpContext.User.Identity.Name))
{
throw;
}
}
//Rest of action body here
//..
//..
}
Ce qui précède semble empêcher les erreurs - mais est-ce sûr?Quelles sont les alternatives?
Merci d'avance.
Meilleures salutations.
ÉDITER:
La "solution" finale était de désactiver la validation des jetons sur le formulaire de connexion - il y a peut-être une meilleure façon de le gérer, mais il semble que toutes les solutions que j'ai trouvées étaient des solutions de contournement moches similaires à la mienne proposée ci-dessus.
Puisqu'il n'y a aucun moyen de savoir à quel point ces alternatives sont "sûres" (si elles le sont), nous avons décidé de désactiver la validation des jetons à la connexion.
Essayez de définir (dans global.cs):
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
Cela ajoutera l'identifiant du nom à votre jeton,
En ce qui concerne le problème de double connexion, essayez d'utiliser un script pour documenter la date et l'heure de la soumission d'origine pour arrêter une deuxième soumission avec le même jeton.
// jQuery plugin to prevent double submission of forms
jQuery.fn.preventDoubleSubmission = function() {
$(this).on('submit',function(e){
var $form = $(this);
if ($form.data('submitted') === true) {
// Previously submitted - don't submit again
e.preventDefault();
} else {
// Mark it so that the next submit can be ignored
$form.data('submitted', true);
}
});
// Keep chainability
return this;
};
Nous savons donc une chose; les utilisateurs aiment le bouton de retour et ont l'habitude du double-clic, c'est un gros problème avec AntiforgeryToken.
Mais selon ce que fait votre application, il existe des moyens de limiter leur contrainte à le faire. La plus simple consiste à faire de votre mieux pour que le visiteur ne se sente pas obligé de "rembobiner" sa demande de modification.
Assurez-vous que la messagerie d'erreur de formulaire est claire et concise pour garantir que l'utilisateur sait ce qui ne va pas. Les erreurs contextuelles donnent des points bonus.
Toujours maintenir l'état du formulaire entre les soumissions de formulaires. Mis à part les mots de passe ou les numéros de carte de crédit, il n'y a aucune excuse grâce aux assistants de formulaire MVC.
@Html.LabelFor(x => x.FirstName)
Si les formulaires sont répartis sur des onglets ou des divs cachés tels que ceux utilisés dans les frameworks SPA comme Angular ou ember.js, soyez intelligent et montrez les dispositions du contrôleur ou le formulaire dont les erreurs sont réellement originaires dans le formulaire soumission lors de l'affichage de l'erreur. Ne vous contentez pas de les diriger vers le contrôleur domestique ou le premier onglet.
"Que se passe-t-il?" - Tenir l'utilisateur informé
Lorsqu'un AntiForgeryToken ne valide pas votre site Web lèvera une Exception de type System.Web.Mvc.HttpAntiForgeryException.
Si vous avez configuré correctement, vous avez activé les erreurs amicales et cela signifie que votre page d'erreur n'affichera pas d'exception et affichera une page d'erreur Nice qui leur indiquera ce qui se passe.
Vous pouvez rendre cela un peu plus facile en donnant au moins à l'utilisateur une page plus informative ciblant 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);
}
}
et votre vue /error/antiforgery
peut leur dire Désolé d'avoir essayé de soumettre les mêmes informations deux fois
Une autre idée est de consigner l'erreur et de renvoyer l'utilisateur à l'écran de connexion:
Créez une classe HandleAntiforgeryTokenErrorAttribute
qui remplace la méthode OnException.
HandleAntiforgeryTokenErrorAttribute.cs:
public class HandleAntiforgeryTokenErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(new { action = "Login", controller = "Account" }));
}
}
Filtre global:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new HandleAntiforgeryTokenErrorAttribute()
{ ExceptionType = typeof(HttpAntiForgeryException) }
);
}
}
J'utiliserais également quelques outils pour enregistrer toutes vos informations car la connexion est une partie essentielle de votre application
NLog pour la journalisation générale et les e-mails sur les exceptions d'applications critiques (y compris les exceptions Web).
Elmah pour le filtrage et le courrier électronique des exceptions Web.
EDIT: Aussi, vous voudrez peut-être regarder un plugin jQuery appelé SafeForm. Lien
MODIFIER:
J'ai vu beaucoup de débats à ce sujet et les points de vue de tout le monde sur le sujet ont des points valables, comment je le vois (extrait de owasp.org )
Cross-Site Request Forgery (CSRF) est une attaque qui force un utilisateur final à exécuter des actions indésirables sur une application Web dans laquelle il est actuellement authentifié , Les attaques CSRF ciblent spécifiquement les demandes de changement d'état, pas le vol de données. Le jeton anti-contrefaçon est spécifique à "qui est connecté". Donc, une fois que vous vous connectez, puis revenez en arrière, l'ancien jeton n'est plus valide
Maintenant, j'utilise également des adresses IP autorisées pour me connecter à mes applications avec une autorisation à 2 facteurs si l'adresse IP des utilisateurs change, donc si la contrefaçon de demande intersite était en jeu, l'utilisateur ne correspondrait pas à l'adresse IP et ne demanderait pas l'autorisation à 2 facteurs. presque comme la façon dont un routeur de sécurité fonctionnerait. mais si vous voulez le garder sur votre page de connexion, je ne vois pas de problème tant que vos pages d'erreur conviviales sont configurées, les gens ne seront pas contrariés car ils verront qu'ils ont fait quelque chose de mal.