ASP.NET Web APIの安全配管

28551 ワード


本編体験ASP.NET Web APIのセキュリティパイプ.ここでの安全配管とは、IIS、HttpModule、OWIN、WebAPIなど、要求および応答中に経験される各コンポーネントまたはプロセスを指す.このパイプラインでは、検証フェーズとライセンスフェーズの2つのフェーズに大別されます.ASP.NET Web API v 1バージョンの場合、セキュリティパイプは大体こうなります:→Authentication、IIS中のHttpModule→Authenticatinへのリクエスト、APIのHttpMessageHandler→Authorizationへのリクエスト、Authorization Filter→Authorizationへのリクエスト、ControlにASP.NET Web APIがv 2バージョンに来たとき、セキュリティパイプは大体:→ホスト内のOWINコンポーネントへの要求→MessageHandlerへの要求、グローバルまたは各要求→Authentication Filterへの要求→Authorization Filterへの要求が表示され、OWINコンポーネントが追加され、OWINはオープンソースであり、Microsoftはこれに基づいてKatana検証ミドルウェアを発行した.ASP.NET Web APIのホストには2つの方式がある:1、Webホスト、ASP.NET,IIS 2,自宿主,WCF,NETプロセスがOWINを考慮すると、1、IIS→ASP.NET+OWIN Bridge→ OWIN→Web API + OWIN Adapter2、Process/Host+OWIN Bridge→OWIN→Web API + OWIN Adapter

一、パイプ内の各部品を理解する


1.1 OWINミドルウェア
 
public class AuthenticationMiddleware
{
    private readonly Func<IDictionary<string, object>, Task> _next;
    
    public AuthenticationMiddleware(Func<IDictionary<string, object>, Task> next)
    {
        _next = next;
    }
    
    public async Task Invoke(IDictionary<string, object> env)
    {
        //  env  ,    
        env["server.user"] = CreatePrincipal();//  principal;
        await _next(env);
    }
}

 
OWINミドルウェアの大まかな動作原理は,要求中のHeader,Body,ルーティングなどの情報がIDictionaryという辞書セットに格納され,取得したユーザ情報をenv["server.user"]に格納し,動作処理IDictionaryセットを呼び出すInvokeメソッドが提供されることである.1.2 Katana Authentication Middleware MicrosoftがOWINに基づいて開発した検証コンポーネントです.
public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticaitonOptions{
            AuthenticationType = "Cookies",
            //more
        });
        
        app.UseGoogleAuthentication(new GoogleAuthenticationOptions{
            AuthenticationType = "Google";
            //more
        });
        
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions{
            AuthenticationType = "Bearer";
            // more
        })
    }
}

以上、少なくともOWINコンポーネントに対して検証方式を選択できることが分かる.1.3 Message Handlerは、グローバルまたはリクエストに実装されます.次のようになります.
public class MyHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        //    
        
        var response = await base.SendAsync(request, cancellationToken);
        
        //    
        return response;
    }
}

 
Message HandlerはASP.からNET WEB API 2以降は存在しない.
 
1.4 Authentication Filter検証フィルタはグローバルに構成できる:WebApiConfig.csconfig.Filters.Add(new HostAuthenticationFilter("Bearer"));もちろん、フィルタはコントローラと方法の面に置くこともできます.
[HostAuthentication("Bearer")]
public class TestController : ApiController
{
    [HostAuthentication("Google")]
    public HttpResponseMessage Get(){}
    
    [OverrideAuthentication]
    [HostAuthentication("Cookies")]
    public HttpResponseMessage Delete(){}
}

 
1.5 Authorization Filterライセンスフィルタ
 
[Authorize]
public class DataController : ApiController
{
    [AllowAnonymous]
    public Data Get(){}
    
    [Authorize(Role = "Foo")]
    public HttpResponseMessage Delete(int id){}
}

認証に失敗した場合は、401エラーを返します.1.6ユーザのIdentityを取得ApiControllerのUser属性からユーザのIdentityを取得する.Userプロパティの値はnullの場合があります.

二、例を通して安全配管を体験する


2.1 HttpModuleをカスタマイズするには、まず、要求が来たら、必ずHttpModuleを通過します.現在のユーザー情報を印刷するには、HttpModuleをカスタマイズする必要があります.
 
namespace SecurityPipeline
{
    public class HttpModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += context_BeginRequest;
        }
        
        void context_BeginRequest(object sender, EventArgs e)
        {
            Helper.Write("HttpModule", HttpContext.Current)
        }
        
        public void Dispose()
        {
        
        }
    }
}

namespace SecurityPiepeline
{
    public static class Helper
    {
        public static void Write(string state, IPrincipal principal)
        {
            Debug.WriteLine("------------" + stage + "--------");
            if(principal == null || principal.Identity == null  || !principal.Identity.IsAuthenticated)
            {
                Debug.WriteLine("anonymous user");
            }
            else
            {
                Debug.WriteLine("User:" + principal.Identity.User);
            }
            
            Debug.WriteLine("
"); } } }

 
HttpContext.CurrentはIPrincipalタイプです.それからこれはWebプロジェクトで、HTTP moduleを登録する必要があります.
 
<configuration>
    <system.webServer>
        <modules>
            <add name="DemoModule" type="SecurityPipeline.HttpModule"/>
        </modules>
    </system.webServer>
</configuration>

 
プロジェクトの下にdefaultがある場合.htmlページでは、プロジェクトを実行し、defaultを表示します.htmlの場合、コンソールには次のような情報が印刷されます.--HttpModule--------anonymouseは明らかに、リクエストが来て、カスタマイズされたHttp Moduleが機能しましたが、IPrincipalからUser情報を取得することはできません.2.2 ASPをインストールする.NET Web API 22.3コントローラの作成
 
using System.Net.Http;
public class TestController : ApiController
{
    public IHttpActionResult Get()
    {
        Helper.Write("Controller", User);
        
        //          
        //Helper.Write("Controller",Request.GetRequestContext().Principal);
        return Ok();
    }
}

 
以上、ApiControllerのUser属性でIPincipalタイプを取得しました.2.4 Microsoftをインストールする.Owin.Host.SystemWeb2.5 Microsoftをインストールします.ASP.NET Web API 2.1 OWIN2.6 Startupクラスの作成
 
using OWin;
using System.Web.Http;

namespace SecurityPopeline
{
    public class Startup
    {
        public void Configuraiton()
        {
            var configuration = new HttpConfiguration();
            configuration.Routes.MapHttpRoute("default", "api/{controller}");
            
        }
    }
}

ここで、WEB APIのHttpConfiguratonインスタンスにクラスOWINのIAppBuilderのUseWebApiメソッドを付与させる.2.7要求ルーティング:localhsot:8000/api/test表示------HttpModule------anonymous user------Controller------anonymous userは、パイプ内のHttpModuleとControllerを経由するように要求されているが、依然としてユーザー情報は取得されていない.2.8 TestMiddlewareクラスを作成してHttpModuleに入った後、Controllerに入る前に、ここはOWINコンポーネントの生存地です.
 
using Microsoft.Owin;

namespace SecurityPopeline.Pipeline
{
    public class TestMiddleware
    {
        private Func<IDictionary<string, object>, Task> _next;
        public TestMiddleware(Func<IDictionary<string, object>, Task> next)
        {
            _next = next;
        }
        
        public async Task Invoke(IDictionary<string, object> env)
        {
            var context = new OwinContext(env);
            Helper.Write("Middleware", context.Request.User);
            await _next(env);
        }
    }
}

 
2.9 StartupクラスにTestMiddlewareセクションを追加
 
using OWin;
using System.Web.Http;

namespace SecurityPopeline
{
    public class Startup
    {
        public void Configuraiton(IAppBuilder app)
        {
            var configuration = new HttpConfiguration();
            configuration.Routes.MapHttpRoute("default", "api/{controller}");
            
            app.Use(typeo(TestMiddleware));
            
            app.UseWebApi(configuration);
        }
    }
}

 
3.10要求ルーティング:localhsot:8000/api/test表示------HttpModule------anonymous user------Middleware------anonymous user------Controller------anonymous user表示され、要求が通るとパイプの中のHttomodule,OWINを経て、最後にControllerに到着し、ユーザー情報を取得できなかった.3.11 TestAuthenticationFilterAttributeクラスをOWINとControllerの間に追加し、認証インタフェースもあります.これも安全配管の重要な一環です.
 
using System.Web.Http.Filters;
using System.Threading.Tasks;

namespace SecurityPipeline.Pipeline
{
    public class TestAuthenticationFilterAttribute : Attribute, IAuthenticationFilter
    {
        public async Task AuthenticateAsync(HttpAuthenticationContext context)
        {
            Helper.Write("AuthenticationFilter", context.ActionContext.RequestContext.Principal, CancellationToken..)
        }
        
        public async Task ChallengeAsync(HttpAuthenticationContext context, CancellationToken..)
        {
        
        }
        
        public bool AllowMultiple
        {
            get {
                return false;
            }
        }
    }
}

 
コントローラフィルタ特性の追加
 
using System.Net.Http;


[TestAuthenticationFilter]
public class TestController : ApiController
{
    public IHttpActionResult Get()
    {
        Helper.Write("Controller", User);
        
        //          
        //Helper.Write("Controller",Request.GetRequestContext().Principal);
        return Ok();
    }
}

 
3.12要求ルート:localhsot:8000/api/test表示------HttpModule------anonymous user------Middleware------anonymous user------AuthenticationFilter------anonymous user------Controller------anonymous userが見え、経路安全配管中のHttpModule,OWINを要求し、検証したが、依然としてユーザー情報を取得していない.3.13 TestAuthorizationFilterAttrbuteクラスを追加すると、認証されたプロパティと、ControllerまたはActionに入る前に、セキュリティパイプにはもう一つの重要なメンバーがいます.
 
public class TestAuthorizationFilterAttribute : AuthorizeAttibute
{
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        Helper.Write("AuthorizationFilter", actionContext.RequestContext.Prioncipal);
        
        return base.IsAuthorized(actionContext);
    }
}

 
コントローラのライセンス機能の追加
 
using System.Net.Http;


[TestAuthenticationFilter]
[TestAuthorizationFilter]
public class TestController : ApiController
{
    public IHttpActionResult Get()
    {
        Helper.Write("Controller", User);
        
        //          
        //Helper.Write("Controller",Request.GetRequestContext().Principal);
        return Ok();
    }
}

 
3.14要求ルート:localhsot:8000/api/test表示------HttpModule------anonymous user------Middleware------anonymous user------AuthenticationFilter------anonymous user------AuthorizationFilter------anonymous userそしてエラー:Authorization has been denied for this requestは、リクエストがControllerに到着する前からエラーを報告していることがわかる.そこで、TestAuthorizationFilterAttrbuteクラスを次のように変更します.
public class TestAuthorizationFilterAttribute : AuthorizeAttibute
{
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        Helper.Write("AuthorizationFilter", actionContext.RequestContext.Prioncipal);
        
        //return base.IsAuthorized(actionContext);
        return true;
    }
}

 
3.15要求ルーティング:localhsot:8000/api/test表示------HttpModule------anonymous user------Middleware------anonymous user------AuthenticationFilter------anonymous user------AuthorizationFilter------anonymous user------anonymous user------anonymous userが表示され、ルーティングは安全なパイプラインを通るHttpModule,OWIN,AuthenticaitonFilter,AuthorizationFilter,Controller,まだユーザー情報が取得されていませんか?3.16ユーザー情報はどこから注入されますか?次にTestMiddlewareクラスを変更します
 
using Microsoft.Owin;
using System.Security.Principal;

namespace SecurityPopeline.Pipeline
{
    public class TestMiddleware
    {
        private Func<IDictionary<string, object>, Task> _next;
        public TestMiddleware(Func<IDictionary<string, object>, Task> next)
        {
            _next = next;
        }
        
        public async Task Invoke(IDictionary<string, object> env)
        {
            var context = new OwinContext(env);
            
            //authentication
            //new string[]      
            context.Request.User = new GenericPrincipal(new GenericIdentity("dom"),new string[]{});
            
            Helper.Write("Middleware", context.Request.User);
            await _next(env);
        }
    }
}

 
3.17要求ルーティング:localhsot:8000/api/test表示------HttpModule------anonymous user------Middleware------User:dom------AuthenticationFilter------User:dom------AuthorizationFilter------User:dom------Controller:domまとめ:通りかかったら、安全配管のHttpModule,OWIN,AuthenticaitonFilter,AuthorizationFilter,Controllerを通り、最後にActionに到着し、ユーザ情報はOWINに注入できる.