I have an ASP.NET MVC / WebAPI / AngularJS application in which I want to implement CSRF protection. I have found some great solutions on this, but am missing one piece of the puzzle. I want to be able to automatically apply a custom AuthorizationAttribute to API nonsafe methods (POST, PUT etc). I hope someone can help.
On the MVC side, I am using the MVC AntiForgeryToken in conjunction with Phil Haacked's ConditionalFilterProvider, configured to apply the ValidateAntiForgeryToken attribute to all POST methods. The technique is explained in this post. The code for the ConditionalFilterProvider is listed below:
using System.Web.Mvc;
public class ConditionalFilterProvider : IFilterProvider
{
private readonly
IEnumerable<Func<ControllerContext, ActionDescriptor, object>> _conditions;
public ConditionalFilterProvider(
IEnumerable<Func<ControllerContext, ActionDescriptor, object>> conditions)
{
_conditions = conditions;
}
public IEnumerable<Filter> GetFilters(
ControllerContext controllerContext,
ActionDescriptor actionDescriptor)
{
return from condition in _conditions
select condition(controllerContext, actionDescriptor) into filter
where filter != null
select new Filter(filter, FilterScope.Global, null);
}
}
For WebAPI, I'm using AngularJS's CSRF protection mechanism, packaged it up with some helper classes for easy implementation on the server, and I'm decorating the API methods with a custom AuthorizeAttribute, as described here.
All this works as intended, but I'd like to go one step further. Following the pattern used for the MVC controllers, I want to create a ConditionalFilterProvider that can be used with WebAPI controllers so that I can ensure that all POST methods are automatically decorated with my custom AuthorizeAttribute.
However, though I've had a stab at creating a ConditionalFilterProvider for WebAPI, I'm not sure I have it right, and can't test it as I don't know how to register it. What I've come up with is:
using System.Web.Http;
public class ConditionalApiFilterProvider : IFilterProvider
{
private readonly
IEnumerable<Func<HttpConfiguration, HttpActionDescriptor, object>> _conditions;
public ConditionalApiFilterProvider(
IEnumerable<Func<HttpConfiguration, HttpActionDescriptor, object>> conditions)
{
_conditions = conditions;
}
public IEnumerable<FilterInfo> GetFilters(
HttpConfiguration configuration,
HttpActionDescriptor actionDescriptor)
{
return from condition in _conditions
select condition(configuration, actionDescriptor) into filter
where filter != null
select new FilterInfo(filter as IFilter, FilterScope.Action);
}
}
And to register it in Application_Start (this doesn't work):
private void ConfigureValidateCsrfHeaderAttribute()
{
//Configure a conditional filter
string[] nonSafeMethods = { "post", "put", "delete" };
IEnumerable<Func<HttpConfiguration, HttpActionDescriptor, object>> conditions =
new Func<HttpConfiguration, HttpActionDescriptor, object>[] {
( c, a ) => nonSafeMethods.Contains("need HTTP method here") ?
new ValidateCsrfHeaderAttribute() : null
};
var provider = new ConditionalApiFilterProvider(conditions);
// This line adds the filter we created above
FilterProviders.Providers.Add(provider); //incorrect provider registration
}
Discovered how to register a custom IFilterProvider for WebAPI, tested the solution and it works correctly. The code needed to register the provider is: