44 votes

Comment puis-je résoudre un AntiForgeryToken exception qui se produit après un iisreset dans mon ASP.Net MVC application?

Je vais avoir des problèmes avec la AntiForgeryToken dans ASP.Net MVC. Si je fais un iisreset sur mon serveur web et un utilisateur se poursuit avec leurs la séance, ils se faire rebondir vers une page de connexion. Pas terrible, mais alors le AntiForgery jeton de souffle et la seule façon d'aller de nouveau, c'est de souffler le cookie sur le navigateur.

Avec la version bêta de la version 1, il sert à aller mal lors de la lecture du cookie pour moi, donc j'ai utilisé pour frotter avant de demander un jeton de validation, mais qui a été résolu quand il a été libéré.

Pour l'instant je pense que je vais revenir à mon code qui fixe la bêta problème, mais je ne peux pas aider mais je pense que je suis absent quelque chose. Est-il une solution plus simple, diable devrais-je tout laisser tomber, de leur aide et en créer un nouveau à partir de zéro? J'ai le sentiment qu'une grande partie du problème est le fait qu'il est si profondément dans l'ancien ASP.Net pipeline et essaie de quelque chose en quelque chose qu'il n'était pas vraiment conçu pour faire.

J'ai eu un coup d'oeil dans le code source de la ASP.Net MVC 2 RC et il ne semble pas que le code a changé beaucoup alors que je n'ai pas essayé, je ne pense pas qu'il y a toutes les réponses.

Voici la partie pertinente de la trace de la pile de l'exception.

Edit: je viens de réaliser que je n'ai pas mentionné que c'est juste essayer d'insérer le jeton sur la requête GET. Ce n'est pas la validation qui se produit lorsque vous faites un POST coup d'envoi.

System.Web.Mvc.HttpAntiForgeryException: A required anti-forgery token was not
supplied or was invalid.
---> System.Web.HttpException: Validation of viewstate MAC failed. If this 
application is hosted by a Web Farm or cluster, ensure that <machineKey> 
configuration specifies the same validationKey and validation algorithm. 
AutoGenerate cannot be used in a cluster.
---> System.Web.UI.ViewStateException: Invalid viewstate. 
  Client IP: 127.0.0.1
  Port: 4991
  User-Agent: scrubbed
  ViewState: scrubbed
  Referer: blah
  Path: /oursite/Account/Login
---> System.Security.Cryptography.CryptographicException: Padding is invalid and
cannot be removed.
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, IVType ivType, Boolean useValidationSymAlgo)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError)
at System.Web.UI.ViewStateException.ThrowMacValidationError(Exception inner, String persistedState)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
at System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState)
at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken)
--- End of inner exception stack trace ---
at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken)
at System.Web.Mvc.HtmlHelper.GetAntiForgeryTokenAndSetCookie(String salt, String domain, String path)
at System.Web.Mvc.HtmlHelper.AntiForgeryToken(String salt, String domain, String path)

44voto

Zhaph - Ben Duguid Points 18573

Si votre MachineKey est configuré pour générer automatiquement, puis la vérification de votre jetons, etc ne survivra pas à un redémarrage de l'application - ASP.NET va générer une nouvelle clé lorsqu'il démarre, et puis ne pas être en mesure de déchiffrer les jetons correctement.

Si vous voyez beaucoup cela, je vous suggère:

  1. La configuration statique MachineKey (vous devriez être en mesure de le faire au niveau de l'application), voir "Comment: Configurer un MachineKey" pour plus d'informations
  2. Essayez de ne pas effectuer IIS se Réinitialise lorsque le site est utilisé1

1 La meilleure façon de le faire est d'avoir un loadbalanced application, qui nécessite une statique MachineKey. Une autre option est de prendre le site vers le bas en plaçant un fichier nommé app_offline.htm à la racine du site, qui va prendre le site en mode hors connexion et afficher votre message - au moins les utilisateurs vont s'attendre à ce que les choses aillent mal.

15voto

Colin Newell Points 1899

Pour l'instant, je suis allé avec une solution qui nettoie le cookie si l'exception est levée. Si l'exception est levée, encore une fois je vais juste laisser faire comme il était.

Je ne vais pas marquer comme " la " réponse, pour l'instant, dans l'espoir que quelqu'un a une meilleure réponse.

public static class MyAntiForgeryExtensions
{
    // Methods
    public static string MyAntiForgeryToken(this HtmlHelper helper)
    {
        return MyAntiForgeryToken(helper, null);
    }

    public static string MyAntiForgeryToken(this HtmlHelper helper, string salt)
    {
        string fragment;
        string path = helper.ViewContext.HttpContext.Request.ApplicationPath;
        try
        {
            fragment = helper.AntiForgeryToken(salt, null, path);
        }
        catch (HttpAntiForgeryException)
        {
            // okay, scrub the cookie and have another go.
            string cookieName = GetAntiForgeryTokenName(path);
            helper.ViewContext.HttpContext.Request.Cookies.Remove(cookieName);
            fragment = helper.AntiForgeryToken(salt, null, path);
        }
        return fragment;
    }

    #region AntiForgeryData code that shouldn't be sealed
    // Copied from AntiForgeryData since they aren't accessible.
    internal static string GetAntiForgeryTokenName(string appPath) {
        if (String.IsNullOrEmpty(appPath)) {
            return "__RequestVerificationToken";
        }
        else {
            return "__RequestVerificationToken_" + Base64EncodeForCookieName(appPath);
        }
    }
    private static string Base64EncodeForCookieName(string s) {
        byte[] rawBytes = Encoding.UTF8.GetBytes(s);
        string base64String = Convert.ToBase64String(rawBytes);

        // replace base64-specific characters with characters that are safe for a cookie name
        return base64String.Replace('+', '.').Replace('/', '-').Replace('=', '_');
    }
    #endregion
}

11voto

JGilmartin Points 1974

j'ai eu ce problème et fixer ce que vous devez faire est d'ajouter explicitement la machine clé de votre site web-config...

<machineKey validationKey="D82960E6B6E9B9029D4CAB2F597B5B4AF631E3C182670855D25FBDE1BFAFE19EFDE92ABBD1020FC1B2AE455D5B5F8D094325597CE1A7F8B15173407199C85A16" decryptionKey="577404C3A13F154908D7A5649EEC8D7C8A92C35A25A3EC078B426BB09D426A71" validation="SHA1" decryption="AES" /> 

Pour vous assurer que vous avez une clé unique, l'utilisation de ce site -> http://aspnetresources.com/tools/machineKey pour générer un unique. il crée même l'ensemble de l'étiquette pour vous.

assurer son placé dans le web.config à l'intérieur...

<system.web>

6voto

4voto

Jeff Points 401

En fait j'ai trouvé que cela fonctionne dans mon ouverture de session de l'action:

    public ActionResult LogOn()
    {
        formsAuthentication.SignOut();

        Response.Cookies.Clear();

        Session[SessionKeys.USER_SESSION_KEY] = null;
        Session.Clear();
        Session.Abandon();


        return View();
    }

L'important était : la Réponse.Les témoins.Clear();

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