使用MVC 4 RC为Web API实现ValidatingAntiForgeryToken属性的问题

Daz*_*kin 19 antiforgerytoken asp.net-mvc-4 asp.net-web-api

我正在制作基于JSON的AJAX请求,并且MVC控制器非常感谢Phil Haack 使用AJAX预防CSRF,以及Johan Driessen 为MVC 4 RC更新了Anti-XSRF.但是,当我将以API为中心的控制器转换为Web API时,我遇到的问题是两种方法之间的功能明显不同,而且我无法转换CSRF代码.

最近ScottS提出了一个类似的问题,Darin Dimitrov 回答了这个问题.Darin的解决方案涉及实现一个调用AntiForgery.Validate的授权过滤器.不幸的是,这段代码对我不起作用(见下一段)而且 - 老实说 - 对我来说太先进了.

据我了解,Phil的解决方案在没有表单元素的情况下制作JSON请求时克服了MVC AntiForgery的问题; 表单元素由AntiForgery.Validate方法假定/预期.我相信这也许就是为什么我也遇到了达林解决方案的问题.我收到一个HttpAntiForgeryException"所需的防伪表单字段'__RequestVerificationToken'不存在".我确定令牌正在被POST(尽管在Phil Haack的解决方案的标题中).这是客户电话的快照:

$token = $('input[name=""__RequestVerificationToken""]').val();
$.ajax({
    url:/api/states",
    type: "POST",
    dataType: "json",
    contentType: "application/json: charset=utf-8",
    headers: { __RequestVerificationToken: $token }
}).done(function (json) {
    ...
});
Run Code Online (Sandbox Code Playgroud)

我尝试通过将Johan的解决方案与Darin's混合在一起来进行攻击,并且能够使事情正常工作但是我正在介绍HttpContext.Current,不确定这是否合适/安全以及为什么我不能使用提供的HttpActionContext.

这是我不雅的混搭......改变是try块中的2行:

public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
    try
    {
        var cookie = HttpContext.Current.Request.Cookies[AntiForgeryConfig.CookieName];
        AntiForgery.Validate(cookie != null ? cookie.Value : null, HttpContext.Current.Request.Headers["__RequestVerificationToken"]);
    }
    catch
    {
        actionContext.Response = new HttpResponseMessage
        {
            StatusCode = HttpStatusCode.Forbidden,
            RequestMessage = actionContext.ControllerContext.Request
        };
        return FromResult(actionContext.Response);
    }
    return continuation();
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  • 我是否认为Darin的解决方案假设存在表单元素?
  • 使用Johan的MVC 4 RC代码将Darin的Web API过滤器混合起来的优雅方法是什么?

提前致谢!

Dar*_*rov 32

您可以尝试从标题中读取:

var headers = actionContext.Request.Headers;
var cookie = headers
    .GetCookies()
    .Select(c => c[AntiForgeryConfig.CookieName])
    .FirstOrDefault();
var rvt = headers.GetValues("__RequestVerificationToken").FirstOrDefault();
AntiForgery.Validate(cookie != null ? cookie.Value : null, rvt);
Run Code Online (Sandbox Code Playgroud)

注意:GetCookies是存在于类扩展方法HttpRequestHeadersExtensions,其是其一部分System.Net.Http.Formatting.dll.它很可能存在于C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\System.Net.Http.Formatting.dll


III*_*III 13

只是想补充一点,这种方法也适用于我(.ajax将JSON发布到Web API端点),尽管我通过继承ActionFilterAttribute并重写OnActionExecuting方法来简化它.

public class ValidateJsonAntiForgeryTokenAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        try
        {
            var cookieName = AntiForgeryConfig.CookieName;
            var headers = actionContext.Request.Headers;
            var cookie = headers
                .GetCookies()
                .Select(c => c[AntiForgeryConfig.CookieName])
                .FirstOrDefault();
            var rvt = headers.GetValues("__RequestVerificationToken").FirstOrDefault();
            AntiForgery.Validate(cookie != null ? cookie.Value : null, rvt);
        }
        catch
        {               
            actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Unauthorized request.");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)