Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.net Core X Forwarded Proto not working

I am working to get my .net core 1.1 application working behind a load balancer and enforcing https. I have the following setup in my Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider, IOptions<Auth0Settings> auth0Settings) {     loggerFactory.AddConsole(Configuration.GetSection("Logging"));     loggerFactory.AddDebug();       var startupLogger = loggerFactory.CreateLogger<Startup>();       if (env.IsDevelopment())     {         app.UseDeveloperExceptionPage();         app.UseDatabaseErrorPage();         app.UseBrowserLink();         startupLogger.LogInformation("In Development");     }     else     {         startupLogger.LogInformation("NOT in development");         app.UseExceptionHandler("/Home/Error");     }      app.UseMiddleware<HttpsRedirectMiddleware>();     app.UseForwardedHeaders(new ForwardedHeadersOptions     {         ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto     });`         app.UseCookieAuthentication(new CookieAuthenticationOptions         {             AuthenticationScheme= CookieAuthenticationDefaults.AuthenticationScheme,             AutomaticAuthenticate = true,             AutomaticChallenge = true,             CookieHttpOnly = true,             SlidingExpiration = true         }); 

The HttpsRedirectMiddleware is for validating the LB has the X-Forwarded-Proto set, it does, and comes back as https as the only value. When I go to the site (https://myapp.somedomain.net), it knows I am not authenticated and redirects me to (http://myapp.somedomain.net/Account/Logon?ReturnUrl=%2f). It loses the SSL connection and switched back over to port 80 on me. The .net core documentation says to use "UseForwardedHeaders" like below, which does not work in my case. The console logger does not have any error or warnings from the middleware when this switch happens.

For a short term fix, I have put this below "UseForwardedHeaders"

    app.Use(async (context, next) =>     {         var xproto = context.Request.Headers["X-Forwarded-Proto"].ToString();         if (xproto!=null && xproto.StartsWith("https", StringComparison.OrdinalIgnoreCase)){             startupLogger.LogInformation("Switched to https");             context.Request.Scheme = "https";         }         await next();      }); 

The above works perfect, but is a hack. I would like to do it the correct way.

like image 709
Josh Avatar asked May 03 '17 00:05

Josh


People also ask

What does X forwarded proto do?

The X-Forwarded-Proto (XFP) header is a de-facto standard header for identifying the protocol (HTTP or HTTPS) that a client used to connect to your proxy or load balancer.

What is Forwardedheadersoptions?

ForwardedHeaders. Identifies which forwarders should be processed. ForwardedHostHeaderName. Gets or sets the header used to retrieve the original value of the Host header field.

How do I get X forwarded in C#?

Request. Headers["X-Forwarded-For"]. Split(new char[] { ',' }). FirstOrDefault();

What is reverse proxy in .NET core?

A reverse proxy is a special type of proxy server that hides the target server to the client. The client requests a resource to the proxy server which retrieves it from another server and provides it to the client. In this case, the client has no idea that the resource comes from another server.


2 Answers

.NET Core has a default set for the forwarded headers. It defaults to 127.0.0.1, for IIS integration.

After tracking down the source code, I found that you can clear the KnownNetworks and KnownProxies lists to accept any forwarded requests. However, it is still best to have a firewall setup or lock the known networks down to a private subnet.

var forwardingOptions = new ForwardedHeadersOptions() {     ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }; forwardingOptions.KnownNetworks.Clear(); // Loopback by default, this should be temporary forwardingOptions.KnownProxies.Clear(); // Update to include  app.UseForwardedHeaders(forwardingOptions); 

Update for .NET Core 2.x: Remember setting the IP of your proxy/load balancer or the private network after debugging the issue. This prevents bypassing your proxy/load balancer and faking the Forwarded-For headers.

services.Configure<ForwardedHeadersOptions>(options => {     options.ForwardLimit = 2;      // Replace with IP of your proxy/load balancer     options.KnownProxies.Add(IPAddress.Parse("192.168.1.5"));      // 192.168.1.0/24 allows any from 192.168.1.1-254;     options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("192.168.1.0"), 24)); }); 

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.2#forwarded-headers-middleware-options

like image 61
Josh Avatar answered Oct 01 '22 03:10

Josh


If you are using a load balancer, it is common to have the load balance terminate the SSL connection and send the request to your application over HTTP.

This worked for me. I am using SSL termination on AWS Load Balancer.

app.UseForwardedHeaders(new ForwardedHeadersOptions {     ForwardedHeaders = ForwardedHeaders.XForwardedProto }); 

What this does is updates the Request.Scheme with the X-Forwarded-Proto header so that all redirects link generation uses the correct scheme.

X-Forwarded-Proto: The scheme from the original client and proxies.

like image 35
Sunil Buddala Avatar answered Oct 01 '22 03:10

Sunil Buddala