Anti forgery with token API and angular

后端 未结 2 1856
情书的邮戳
情书的邮戳 2020-12-12 01:44

I am working on Angular 6 application with SSO login and .net core web API. The code hits the back end on /token url first time which is a post operation. How do I do the an

相关标签:
2条回答
  • 2020-12-12 02:28

    I'm not sure if that's what you're looking for, but I'll try to explain how I achieved it in a similar case.

    First of all Angular has built in helpers for XSRF handling:

    • https://angular.io/guide/security#http
    • https://angular.io/api/common/http/HttpClientXsrfModule
    • https://angular.io/api/common/http/HttpXsrfTokenExtractor

    So the hardest part is to create custom XSRF middleware at api level.

    I did it some time ago for one of my apps which was built with Angular 6 on the front and ASP.NET Core WebApi on the back-end.

    Article which help me with it:

    • https://www.domstamand.com/secure-your-angularasp-net-core-application-with-anti-forgery-token/

    Your middleware could look like this:

    public class AntiForgeryTokenMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly IAntiforgery _antiforgery;
    
        public AntiForgeryTokenMiddleware(RequestDelegate next, IAntiforgery antiforgery)
        {
            _next = next;
            _antiforgery = antiforgery;
        }
    
        public Task Invoke(HttpContext context)
        {
            if (context.Request.Path.Value.IndexOf("/your api endpoint, e.g. /api", StringComparison.OrdinalIgnoreCase) != -1)
            {
                var tokens = _antiforgery.GetAndStoreTokens(context);
                context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false, Secure = false });
            }
            return _next(context);
        }
    }
    

    Then as per mentioned article you have to add it to services in ConfigureServices method of Startup class:

    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
    

    And use it in Configure method:

    app.UseAntiforgeryToken();
    

    And of course to make use of it you have to decorate your api methods with [ValidateAntiForgeryToken] attribute.

    Then in your Angular app you could create HttpInterceptor to send token only when it's needed.

        @Injectable()
        export class XsrfInterceptor implements HttpInterceptor {
    
        constructor(private tokenExtractor: HttpXsrfTokenExtractor) {}
    
        private actions: string[] = ["POST", "PUT", "DELETE"];
        private forbiddenActions: string[] = ["HEAD", "OPTIONS"];
    
        intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
            let token = this.tokenExtractor.getToken();
            let permitted =  this.findByActionName(request.method, this.actions);
            let forbidden =  this.findByActionName(request.method, this.forbiddenActions);;
    
            if (permitted !== undefined && forbidden === undefined && token !== null) {
                request = request.clone({ setHeaders: { "X-XSRF-TOKEN": token } });
            }
    
            return next.handle(request);
        }
    
        private findByActionName(name: string, actions: string[]): string {
            return actions.find(action => action.toLocaleLowerCase() === name.toLocaleLowerCase());
        }
    }
    
    0 讨论(0)
  • 2020-12-12 02:29

    This question is old however my solution could help somebody. What worked for us:

    • on Angular FE side HttpXsrfTokenInterceptor is used which is setting X-XSRF-TOKEN header. Of course cookie has to contain token under XSRF-TOKEN

    • on .net core side: Basically approach describe above, using domstamand's approach. However, and this is important, you have to add validation action into the middleware. Apparently using your custom middlaware turn's off validation done OOB by .net core antiforgery service. So after update your code for Invoke method should looks like this:

       public Task Invoke(HttpContext context)
       {
           if (context.Request.Headers.ContainsKey("X-XSRF-TOKEN"))
           {
               _antiForgery.ValidateRequestAsync(context);
           }
      
           var tokens = _antiForgery.GetAndStoreTokens(context);
           context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions { 
               HttpOnly = false,
               Secure = true
           });
      
           return _next(context);
       }
      

    I added check for X-XSRF-TOKEN to avoid possible issues e.g. when GET or OPTIONS preflight check is called.

    Update: Problem with my solution is that if you don't include X-XSRF-TOKEN into the HTTP request header validation doesn't execute at all. I trying to find fix for that.

    0 讨论(0)
提交回复
热议问题