3

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
    }
4

1 に答える 1

3

WebAPI 用のカスタム IFilterProvider を登録する方法を発見し、ソリューションをテストしたところ、正しく動作しました。プロバイダーを登録するために必要なコードは次のとおりです。

using System.Web.Http;
using System.Web.Http.Filters;

private void ConfigureValidateCsrfHeaderAttribute()
{
    //Configure a conditional filter
    HttpMethod[] nonSafeMethods = { HttpMethod.Post, HttpMethod.Put, HttpMethod.Delete };
    IEnumerable<Func<HttpConfiguration, HttpActionDescriptor, object>> conditions =
        new Func<HttpConfiguration, HttpActionDescriptor, object>[] {
                ( c, a ) => nonSafeMethods.Any(m => a.SupportedHttpMethods.Contains(m)) ?
                new ValidateCsrfHeaderAttribute() : null
    };

    var provider = new ConditionalApiFilterProvider(conditions);

    // This line adds the filter we created above
    GlobalConfiguration.Configuration.Services.Add(typeof(IFilterProvider), provider);
}
于 2013-12-03T15:20:49.077 に答える