CSRF 保護を実装したい ASP.NET MVC / WebAPI / AngularJS アプリケーションがあります。これについていくつかの優れた解決策を見つけましたが、パズルのピースが 1 つ欠けています。カスタム AuthorizationAttribute を API の安全でないメソッド (POST、PUT など) に自動的に適用できるようにしたいと考えています。誰かが助けてくれることを願っています。
MVC 側では、ValidateAntiForgeryToken 属性をすべての POST メソッドに適用するように構成されたPhil Haacked の ConditionalFilterProviderと組み合わせて MVC AntiForgeryToken を使用しています。テクニックはこの投稿で説明されています。ConditionalFilterProvider のコードを以下に示します。
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);
}
}
WebAPI については、AngularJS の CSRF 保護メカニズムを使用しており、サーバー上で簡単に実装できるようにいくつかのヘルパー クラスでパッケージ化し、ここで説明されているようにカスタム AuthorizeAttribute で API メソッドを装飾しています。
これはすべて意図したとおりに機能しますが、さらに一歩進めたいと思います。MVC コントローラーで使用されるパターンに従って、WebAPI コントローラーで使用できる ConditionalFilterProvider を作成して、すべての POST メソッドがカスタムの AuthorizeAttribute で自動的に装飾されるようにします。
ただし、WebAPI 用の ConditionalFilterProvider の作成に苦労しましたが、それが正しいかどうか確信が持てず、登録方法がわからないためテストできません。私が思いついたのは次のとおりです。
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);
}
}
そして、それを Application_Start に登録するには (これは機能しません):
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
}