我们有一个包含多种表单的页面。每个人都有自己的
@Html.AntiForgeryToken()
。在我的本地机器上一切都很棒。
我们部署到 Azure (PAAS),但
__RequestVerificationToken
并未根据每个请求创建。有时它在那里,有时我收到所需的防伪 cookie 不存在,很少收到令牌不匹配错误。
我现在完全一无所知。我不知道我们的代码或Azure环境是否有问题?这些形式中没有 ajax。
我们已将
<machineKey>
部分添加到我们的 web.config 中。没有缓存。有时它从第一次就出现在新设备上。
在花费大量时间进行调查后,结合使用 Sentry 和 Azure Web 服务器日志,我发现了上述错误的 2 个主要原因:
1)在手机上,当浏览器处于后台时,操作系统可能会突然停止浏览器以释放资源。发生这种情况时,通常页面会存储在手机驱动器上,并在重新打开浏览器后从那里重新加载。
然而,问题是,此时,防伪令牌(即会话 cookie)已经过期,因为这本质上是一个新会话。因此,页面加载时没有防伪 Cookie,而是使用上一个会话中的 HTML。这会导致
The required anti-forgery cookie is not present
异常。
2) 虽然看似相关,但
tokens do not match
例外通常只是无关紧要的相关。原因似乎是同时打开多个选项卡的用户行为。
仅当用户到达包含表单的页面时才会分配防伪 Cookie。这意味着他们可以访问您的主页,并且没有防伪 cookie。然后他们可以使用中键单击打开多个选项卡。多个选项卡是多个并行请求,每个请求都没有防伪 cookie。
由于这些请求没有防伪 cookie,因此 ASP.NET 会为每个请求生成一个单独的伪随机令牌,并在表单中使用该令牌;但是,仅保留最后接收到的标头的结果。这意味着所有其他页面将在页面上具有无效令牌,因为它们的防伪 cookie 已被覆盖。
对于解决方案,我创建了一个全局过滤器,应确保
下面的代码是一个
FilterAttribute
,必须作为全局过滤器添加到FilterConfig.cs
内。 请注意,虽然我不认为这会造成安全漏洞,但我绝不是安全专家,因此欢迎任何意见。
[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)
{
}
}
我相信您的问题来自于在一页上有多个带有不同防伪令牌的表单。 当请求页面时,您会在表单隐藏字段中获得两个不同的令牌,但在 cookie 中仅获得一个令牌。 表单 POST 包含导致错误的不匹配标记。
如果页面仅包含一个表单,请尝试 AFT 如何为您工作。如果它工作正常那么我的假设是正确的。
这个答案包含具有多种表单的页面的可能解决方案,但它有一些安全缺陷,如here所述。
我不确定为什么在您的本地主机上一切正常。 我创建了简单的应用程序,并尝试使用正确的 cookies 令牌但使用上一个会话中的旧表单令牌来进行表单 POST。令我惊讶的是,这样的 POST 成功通过了。 在这种情况下,asp.net 可能对本地请求进行了一些特殊处理。我没有找到任何这方面的信息。
如果我的回答还是没有帮助到您,请您提供以下数据以供进一步分析:
只有在推送到服务器后,我才遇到同样的问题,在本地主机中测试后,情况很好,之后