Shannon Deminick's blog all about web development

How to change HttpRequest.IsSecureConnection

December 15, 2020 13:27

This post is for ASP.NET Framework, not ASP.NET Core

This is an old problem that is solved in dozens of different ways…

Typically in an ASP.NET Framework site when you need to check if the request is running in HTTPS you would do something like HttpContext.Request.IsSecureConnection. But this value won’t return the anticipated value if your site is running behind a proxy or load balancer which isn’t forwarding HTTPS traffic and instead is forwarding HTTP traffic. This is pretty common and the way people deal with it is to check some special headers, which will vary depending on the load balancer you are using. The primary one is HTTP_X_FORWARDED_PROTO but there are others too like: X-Forwarded-Protocol, X-Forwarded-Ssl, X-Url-Scheme , and the expected values for each are slightly different too.

So if you can’t rely on HttpContext.Request.IsSecureConnection then you’ll probably make an extension method, or better yet an abstraction to deal with checking if the request is HTTPS. That’s totally fine but unfortunately you can’t rely on all of the dependencies your website uses to deal with this scenario. You’d also need to be able to configure them all to possibly handle some weird header scheme that your proxy/load balancer uses.

Aha! HttpRequestBase is abstract

If you are using MVC you’ll probably know that the HttpContext.Request within a controller is HttpRequestBase which is an abstract class where it’s possible to re-implement IsSecureConnection. Great, that sounds like a winner! Unfortunately this will only get you as far as being able to replace that value within your own controllers, this will still not help you with the dependencies your website uses.

And controllers aren’t the only thing you might need to worry about. You might have some super old ASP.NET Webforms or other code lying around using HttpContext.Current.Request.IsSecureConnection which is based on the old HttpRequest object which cannot be overridden.

So how does the default HttpContext.Current get this value?

The HttpContextBase is based on HttpContextWrapper which simply wraps HttpContext.Current. This is what is passed to your MVC controllers. As for HttpContext.Current, this is the source of all of this data and with a bit (a LOT) of hacking you can actually change this value.

The HttpContext.Current is actually a set-able singleton value. The constructor of HttpContext has 2x overloads, one that takes in a request/response object and another that accepts something called HttpWorkerRequest. So it is possible (sort of) to construct a new HttpContext instance that wraps the old one … so can we change this value? Yes!

HttpWorkerRequest is an abstract class and all methods are overridable so if we can access the underlying default HttpWorkerRequest (which is IIS7WorkerRequest) from the current context, we could wrap it and return anything we want for IsSecureConnection. This is not a pretty endeavor but it can be done.

Wrapping the HttpContext

I created a gist to show this. The usage is easy, just create an IHttpModule and replace the HttpContext by using a custom HttpWorkerRequest instance that accepts a delegate to return whatever you want for IsSecureConnection:

Now to create the wrapper, there’s a ton of methods and properties to override:

So what about OWIN?

Owin is easy to take care of, it’s OwinContext.Request.IsSecure is purely based on whether or not the scheme is https and the .Scheme property is settable:

Does this all actually work?

This was an experiment to see how possible this is and based on my rudimentary tests, yes it works. I have no idea if this will have some strange side affects but in theory its all just wrapping what normally executes. There will be a small performance penalty because this is going to create a couple of new objects each request and use a reflection call but I think that will be very trivial.

Let me know if it works for you!