Après avoir passé une quantité importante de temps à l'enquête, en utilisant une combinaison de journaux de serveur Web Sentry et Azure, j'ai trouvé 2 principales causes des erreurs mentionnées:
1) Sur les téléphones mobiles, quand le navigateur est en arrière-plan, il peut être brusquement arrêté par le système d'exploitation pour libérer des ressources. Lorsque cela se produit, généralement, la page est stockée sur le lecteur du téléphone et rechargée à partir de là une fois le navigateur rouvert. Cependant, le problème est que le jeton Anti-Forgery, qui est un cookie de session, a déjà expiré, car il s'agit essentiellement d'une nouvelle session. Ainsi, la page se charge sans un anti-falsification de cookies, en utilisant le code HTML de la session précédente. Cela provoque l'exception The required anti-forgery cookie is not present
.
2) Bien qu'apparemment apparentée, l'exception tokens do not match
n'est généralement liée que de manière tangentielle. La cause semble être le comportement de l'utilisateur d'ouvrir plusieurs onglets en même temps.Le cookie anti-falsification n'est attribué que lorsqu'un utilisateur arrive sur une page contenant un formulaire. Cela signifie qu'ils peuvent aller à votre page d'accueil, et n'ont pas de cookie anti-falsification. Ensuite, ils peuvent ouvrir plusieurs onglets en utilisant le clic du milieu. Les multiples onglets sont des requêtes parallèles multiples, chacune sans cookie anti-falsification. Comme ces requêtes n'ont pas de cookie anti-falsification, pour chacune d'elles, ASP.NET génère un jeton pseudo-aléatoire distinct pour leur cookie, et l'utilise dans le formulaire; cependant, seul le résultat du dernier en-tête reçu sera conservé. Cela signifie que toutes les autres pages auront des jetons invalides sur la page, puisque leur cookie anti-falsification a été remplacé.
Pour une solution, j'ai créé un filtre global qui devrait veiller à ce que
- Le cookie Anti-Contrefaçon est attribué sur une page, même si la page n'a pas de forme, et
- Anti -Le cookie Forgery n'est pas lié à une session. Sa durée de vie devrait être ajustée pour correspondre au jeton de connexion de l'utilisateur, mais elle devrait persister entre les sessions au cas où un appareil mobile rechargerait la page sans la session.
Le code ci-dessous est un FilterAttribute
qui doit être ajouté à l'intérieur de FilterConfig.cs
en tant que filtre global. Veuillez noter que, bien que je ne crois pas que cela créerait un trou de sécurité, je ne suis en aucun cas un expert en sécurité, donc toute contribution est la bienvenue.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AntiForgeryFilter : FilterAttribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var cookie = filterContext.HttpContext.Request.Cookies.Get(AntiForgeryConfig.CookieName);
var addCookie = true;
if (string.IsNullOrEmpty(cookie?.Value))
{
cookie = filterContext.HttpContext.Response.Cookies.Get(AntiForgeryConfig.CookieName);
addCookie = false;
}
if (string.IsNullOrEmpty(cookie?.Value))
{
AntiForgery.GetTokens(null, out string cookieToken, out string _);
cookie = new HttpCookie(AntiForgeryConfig.CookieName, cookieToken)
{
HttpOnly = true,
Secure = AntiForgeryConfig.RequireSsl
};
}
cookie.Expires = DateTime.UtcNow.AddYears(1);
if(addCookie) filterContext.HttpContext.Response.Cookies.Add(cookie);
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
Avez-vous déjà trouvé la réponse? –
Non, nous avons dû supprimer le contrôle antiforgery (il était utilisé pour les formulaires d'intégration simples, rien de critique à ce sujet). Notre installation Azure avait deux CD logiques, donc je suppose que c'est lié à différents CDs gérant la requête et la réponse. C'est juste ma conjecture. – TamerM
Je suis triste d'entendre cela, bien que je ne pense pas que cela devrait poser problème à moins que vous ayez le domaine défini dans l'action de formulaire (qui redirigera alors l'utilisateur vers un autre CD pour le POST, mais je doute que ce serait le cas puisque si vous utilisiez l'UrlHelper, cela ne redirige pas les utilisateurs entre les domaines). –