【问题标题】:AntiForgery.Validate Always Validates Even When no MatchAntiForgery.Validate 始终验证,即使没有匹配
【发布时间】:2016-09-20 11:11:26
【问题描述】:

我有一个类用于执行防伪令牌验证,其中有效负载是 Json。这个类看起来像这样(来自 Phil Haacked):

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ValidateJsonAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        if (ReferenceEquals(filterContext, null)) throw new ArgumentNullException("filterContext");

        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {
            //  Ajax POSTs and normal form posts have to be treated differently when it comes
            //  to validating the AntiForgeryToken
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = ReferenceEquals(antiForgeryCookie, null) ? null : antiForgeryCookie.Value;

                AntiForgery.Validate(cookieValue, request.Headers[AntiForgeryConfig.CookieName]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute().OnAuthorization(filterContext);
            }
        }

    }
}

这是我使用它的第一个 Angular 项目,它并没有在我期望的地方抛出异常。例如,标头中的值与 cookie 中的值不同,并且对 AntiForgery.Validate 的调用无一例外地继续进行。

防伪令牌在 shell 视图中呈现(即 Index.cshtml),并添加到 Angular 模块运行函数的标头中:

// Handle routing errors and success events
theApp.run(['$http', '$route', '$rootScope', '$q', 'routeOverlord',
    function ($http, $route, $rootScope, $q, routeOverlord) {
        // Include $route to kick start the router.
        routeOverlord.setRoutingHandlers();

        // Include AntiForgeryToken to prevent CSRF attacks
        $http.defaults.headers.common['__RequestVerificationToken'] = angular.element('input[name="__RequestVerificationToken"]').val();
    }]);

这是众所周知的事情吗?如果需要,很高兴提供 cookie 和标头中不同字符串的 Fiddler 屏幕截图。

干杯

【问题讨论】:

  • 没时间测试,但是AntiForgery.Validate(cookieValue, request.Headers[AntiForgeryConfig.CookieName]);这一行不应该是在寻找一个名称为__RequestVerificationToken而不是AntiForgeryConfig.CookieName的标题
  • @SBurris AntiForgeryConfig.CookieName 是该框架类上的静态字符串,解析为 __RequestVerificationToken

标签: asp.net asp.net-mvc-5 antiforgerytoken


【解决方案1】:

cookie 令牌和表单令牌(在您的情况下位于标题中的那个)应该是相同的(更容易伪造)。

cookie 令牌包含一个随机 blob。表单标记包含相同的 blob,以及一些身份数据(以及可选的一些附加数据)。

AntiForgery.Validate() 检查两个 blob 是否相同,以及表单令牌中的其他数据是否对应于身份数据和可选的附加数据。

【讨论】:

  • 谢谢菲利普。这听起来很有道理。足够好。
  • 是否有关于这种行为的任何实际文档?您是如何或在哪里发现的?
  • @DrazenBjelovuk 我不知道是否有任何文档。我从带有 Reflector 的 .NET 代码中找到了它(特别是 AntiForgeryWorker.GetAntiForgeryAndSetCookie() 和 .Validate() 方法)。
【解决方案2】:

我也看到了。 cookie 值和字段值不同,但 .Net 框架仍然允许它们通过。

这是因为 .Net Framework 的实现比简单的值匹配检查要复杂一些。

查看 Github 上的源代码后,发现令牌包含除 GUID 之外的其他信息(它们将其绑定到当前用户)。

我可以从 TokenValidator 中看到 cookie 值是表示 SessionToken 的令牌,其中字段值(您的标头值)不应该是会话令牌。

// Do the tokens have the correct format?
if (!sessionToken.IsSessionToken || fieldToken.IsSessionToken)
{
    throw HttpAntiForgeryException.CreateTokensSwappedException(_config.CookieName, _config.FormFieldName);
}

但它们仍然用于验证操作确实来自授权用户,而不是来自恶意人员的一些预先准备好的攻击。

我个人需要对微软的实施做更多的研究,但从我现在看到的一点点(以及下面的链接)来看,这些值肯定会有所不同。

我看过的参考资料:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-09
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    • 1970-01-01
    • 2018-12-23
    • 2013-10-01
    相关资源
    最近更新 更多