Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Request.Url.Scheme gives http instead of https on load balanced site

Tags:

c#

asp.net-mvc

I am testing a new load balanced staging site and the https is set up at the load balancer level, not at the site level. Also, this site will be always https so i don't need remote require https attributes etc. The url displays https but it is not available in my code. I have a few issues due to this reason

Request.Url.Scheme is always http:

public static string GetProtocol()         {             var protocol = "http";             if (HttpContext.Current != null && HttpContext.Current.Request != null)             {                 protocol = HttpContext.Current.Request.Url.Scheme;             }             return protocol;         } 

Same thing with this base url, protocol is http

public static string GetBaseUrl()         {             var baseUrl = String.Empty;              if (HttpContext.Current == null || HttpContext.Current.Request == null || String.IsNullOrWhiteSpace(HttpRuntime.AppDomainAppPath)) return baseUrl;              var request = HttpContext.Current.Request;             var appUrl = HttpRuntime.AppDomainAppVirtualPath;              baseUrl = string.Format("{0}://{1}{2}", request.Url.Scheme, request.Url.Authority, appUrl);              if (!string.IsNullOrWhiteSpace(baseUrl) && !baseUrl.EndsWith("/"))                 baseUrl = String.Format("{0}/", baseUrl);              return baseUrl;         } 

Now the biggest issue is referencing js files and google fonts referenced in the style sheets. I am using // here without http or https but these are treated as http and i see mixed content blocked message in FireBug.

How can i overcome this issue?

like image 455
learning... Avatar asked May 12 '15 16:05

learning...


2 Answers

As you've said HTTPS termination is done at load balancer level ("https is set up at the load balancer level") which means original scheme may not come to the site depending on loadbalancer configuration.

It looks like in your case LB is configured to talk to site over HTTP all the time. So your site will never see original scheme on HttpContext.Request.RawUrl (or similar properties).

Fix: usually when LB, proxy or CDN configured such way there are additional headers that specify original scheme and likely other incoming request parameters like full url, client's IP which will be not directly visible to the site behind such proxying device.

like image 70
Alexei Levenkov Avatar answered Sep 17 '22 10:09

Alexei Levenkov


I override the ServerVariables to convince MVC it really is communicating through HTTPS and also expose the user's IP address. This is using the X-Forwarded-For and X-Forwarded-Proto HTTP headers being set by your load balancer.

Note that you should only use this if you're really sure these headers are under your control, otherwise clients might inject values of their liking.

public sealed class HttpOverrides : IHttpModule {     void IHttpModule.Init(HttpApplication app)     {         app.BeginRequest += OnBeginRequest;     }      private void OnBeginRequest(object sender, EventArgs e)     {         HttpApplication app = (HttpApplication)sender;          string forwardedFor = app.Context.Request.Headers["X-Forwarded-For"]?.Split(new char[] { ',' }).FirstOrDefault();         if (forwardedFor != null)         {             app.Context.Request.ServerVariables["REMOTE_ADDR"] = forwardedFor;             app.Context.Request.ServerVariables["REMOTE_HOST"] = forwardedFor;         }          string forwardedProto = app.Context.Request.Headers["X-Forwarded-Proto"];         if (forwardedProto == "https")         {             app.Context.Request.ServerVariables["HTTPS"] = "on";             app.Context.Request.ServerVariables["SERVER_PORT"] = "443";             app.Context.Request.ServerVariables["SERVER_PORT_SECURE"] = "1";         }     }      void IHttpModule.Dispose()     {     } } 

And in Web.config:

<system.webServer>     <modules runAllManagedModulesForAllRequests="true">         <add name="HttpOverrides" type="Namespace.HttpOverrides" preCondition="integratedMode" />     </modules> </system.webServer> 
like image 28
Bouke Avatar answered Sep 19 '22 10:09

Bouke