使用WebApi时,防伪cookie令牌和表单字段令牌不匹配

SB2*_*055 9 asp.net asp.net-mvc csrf antiforgerytoken asp.net-web-api

我有一个单页面的应用程序(用户加载一堆HTML/JS,然后在没有另一次调用MVC的情况下发出AJAX请求 - 仅通过WebAPI).在WebAPI中,我有以下内容:

public sealed class WebApiValidateAntiForgeryTokenAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(
        System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        if (actionContext == null)
        {
            throw new ArgumentNullException(nameof(actionContext));
        }
        if (actionContext.Request.Method.Method == "POST")
        {
            string requestUri = actionContext.Request.RequestUri.AbsoluteUri.ToLower();
            if (uriExclusions.All(s => !requestUri.Contains(s, StringComparison.OrdinalIgnoreCase))) // place some exclusions here if needed
            {
                HttpRequestHeaders headers = actionContext.Request.Headers;

                CookieState tokenCookie = headers
                    .GetCookies()
                    .Select(c => c[AntiForgeryConfig.CookieName]) // __RequestVerificationToken
                    .FirstOrDefault();

                string tokenHeader = string.Empty;
                if (headers.Contains("X-XSRF-Token"))
                {
                    tokenHeader = headers.GetValues("X-XSRF-Token").FirstOrDefault();
                }

                AntiForgery.Validate(!string.IsNullOrEmpty(tokenCookie?.Value) ? tokenCookie.Value : null, tokenHeader);
            }

        }
        base.OnActionExecuting(actionContext); // this is where it throws
    }
}
Run Code Online (Sandbox Code Playgroud)

在Global.asax注册:

    private static void RegisterWebApiFilters(HttpFilterCollection filters)
    {
        filters.Add(new WebApiValidateAntiForgeryTokenAttribute());
        filters.Add(new AddCustomHeaderFilter());
    }
Run Code Online (Sandbox Code Playgroud)

偶尔,我The anti-forgery cookie token and form field token do not match在日志中看到错误.当发生这种情况,双方tokenCookie.valuetokenHeader没有空.

客户端,我的所有AJAX请求都使用以下内容:

beforeSend: function (request) {
     request.setRequestHeader("X-XSRF-Token", $('input[name="__RequestVerificationToken"]').attr("value"););
},
Run Code Online (Sandbox Code Playgroud)

使用Razor在SPA页面上生成令牌一次:

@Html.AntiForgeryToken()
Run Code Online (Sandbox Code Playgroud)

我在Web.config中设置了我的机器密钥.

可能是什么导致了这个?

更新 我只是检查了日志,我有时也会看到这个:

提供的防伪令牌适用于用户"",但当前用户为"someuser@domain.com".几秒钟前

当用户在登录时刷新其SPA实例时会发生这种情况.由于某种原因,SPA会将它们放入登录页面而不是内页(User.Identity.IsAuthenticated是真的) - 然后由于此错误他们无法登录.清爽将它们拉回来.不知道这意味着什么,但我认为更多的信息不会伤害.

附录 https://security.stackexchange.com/questions/167064/is-csrf-protection-useless-with-ajax/167076#167076

Fab*_*ien 4

我的回答建议不要尝试在 AJAX 调用中使用基于令牌的 CSRF 保护,而是依赖 Web 浏览器的本机 CORS 功能。

\n\n

基本上,从浏览器到后端服务器的任何 AJAX 调用都会检查域来源(也称为加载脚本的域)。如果域匹配(JS 托管域 == 目标 AJAX 服务器域),则 AJAX 调用执行正常,否则返回null.

\n\n

如果攻击者尝试在自己的服务器上托管恶意 AJAX 查询,并且您的后端服务器没有 CORS 策略允许他这样做(默认情况下是这种情况),那么攻击将会失败。

\n\n

因此,本质上,CSRF 保护在 AJAX 调用中毫无用处,您可以通过不尝试处理该问题来降低技术债务

\n\n

更多信息:- Mozilla 基金会

\n\n

代码示例 - 使用您的控制台检查器!

\n\n

\r\n
\r\n
<html>\r\n<script>\r\nfunction reqListener () {\r\n  console.log(this.responseText);\r\n}\r\n\r\nvar oReq = new XMLHttpRequest();\r\noReq.addEventListener("load", reqListener);\r\noReq.open("GET", "http://www.reuters.com/");\r\noReq.send();\r\n</script>\r\n</html>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

运行它并查看安全错误:

\n\n
\n

跨源请求被阻止:同源策略不允许读取http://www.reuters.com/上的远程资源。(原因:CORS 标头\n \xe2\x80\x98Access-Control-Allow-Origin\xe2\x80\x99 丢失)。

\n
\n\n

Mozilla 对于跨站点 XMLHttpRequest的实现非常清楚:

\n\n
\n

现代浏览器通过实施 Web 应用程序 (WebApps) 工作组的跨站点请求访问控制标准来支持跨站点请求。

\n\n

只要服务器配置为允许来自 Web 应用程序源的请求,XMLHttpRequest 就可以工作。否则,将引发\n INVALID_ACCESS_ERR 异常。

\n
\n