5 votes

MVC ValidateAntiForgeryToken : problème des onglets multiples

Nous obtenions des erreurs du type "A required anti-forgery token was not supplied or was invalid.", et après quelques recherches supplémentaires, j'ai réussi à recréer le problème dans sa forme la plus simple - soit je fais quelque chose de complètement faux, soit il s'agit d'une limitation du système de jetons anti-falsification.

Dans tous les cas, j'aimerais avoir des conseils !

Projet MVC 2 vide : une page de vue, un contrôleur

vue :

<%--Sign in form:--%>
<% using(Html.BeginForm("SignIn", "Home", FormMethod.Post)) {%>
    <%= Html.AntiForgeryToken()%>
    <input type="submit" value="Sign in" />
<%}%>

Contrôleur :

public ActionResult Index()
{
    ViewData["status"] = "Index";
    return View();
}

[ValidateAntiForgeryToken]
public ActionResult SignIn()
{
    ViewData["status"] = "Signed In!";
    FormsAuthentication.SetAuthCookie("username", false);
    return View("Index");
}

[EDIT : exemple de code simplifié]

Afin de recréer l'exception, ouvrez deux onglets non signés - connectez-vous sur le premier onglet, puis connectez-vous sur le second.

Le deuxième onglet déclenchera toujours une exception anti-falsification, alors que le comportement correct serait de rediriger vers la page de connexion (en partageant la session/authentification de l'onglet de connexion original).

Tout conseil serait apprécié !

A la vôtre, Dave

5voto

Naz Points 664

En regardant le code source de MVC 2, il semble que le champ caché AntiForgeryToken inclut le User.Identity.Name sérialisé, si vous êtes connecté. À la ligne 69 de la page ValidateAntiForgeryTokenAttribute il semble alors vérifier votre jeton avec le nom actuel de User.Identity.Name.

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

Parce que dans votre autre onglet, vous êtes maintenant connecté, le code ci-dessus invalide le jeton existant qui ne contient pas le nom User.Identity.Name.

Cela pourrait être corrigé en ajoutant un !string.IsNullOrEmpty(formToken.Username) pour contourner ce contrôle, mais je ne sais pas si cela posera des problèmes de sécurité et si cela implique d'avoir un build MVC 2 personnalisé.

0voto

Darin Dimitrov Points 528142

Vous pouvez utiliser le même sel :

<% using(Html.BeginForm("SignIn", "Home", FormMethod.Post)) {%>
    <%= Html.AntiForgeryToken("123")%>
    <input type="submit" value="Sign in" />
<%}%>

<% using(Html.BeginForm("Protected", "Home", FormMethod.Post)) {%>
    <%= Html.AntiForgeryToken("456")%>
    <input type="submit" value="Do secret stuff" />
<%}%>

Et dans votre contrôleur :

[ValidateAntiForgeryToken(Salt = "123")]
public ActionResult SignIn()
{
    ViewData["status"] = "Signed In!";
    FormsAuthentication.SetAuthCookie("username", false);
    return View("Index");
}

[Authorize]
[ValidateAntiForgeryToken(Salt = "456")]
public ActionResult Protected()
{
    ViewData["status"] = "Authed";
    return View("Index");
}

Faites de même avec l'autre jeton mais assurez-vous de choisir un différents sel.

-2voto

Dave Bish Points 7943

La vraie réponse à ce problème est simplement que vous ne devriez pas utiliser de jeton anti-falsification sur les formulaires de connexion !

Il est inutile de "forger" le fait d'être un utilisateur sur une formulaire de connexion - ils ne sont pas connectés !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X