Working with HTTPS on a Unique IP in a Load Balanced Environment

Michael OssouTimes have changed. While VPS, traditional and dedicated hosting solutions still have some use cases, the truth is, it’s 2014 and those legacy solutions are losing relevancy by the hour. Today’s cloud – the real cloud – is a much better solution.

As with anything however, we need to adjust. Take for example the use of HTTPS. If you’re using an SNI SSL solution, you’re in the clear. The security information for your cert lives in the load balancers and is available to all of the web servers, so there is nothing else you have to do to use HTTPS.

However, if you are using a unique IP-based SSL solution, there are some things to consider. In this article I’m going to cover a few of the key points.

For the purposes of context, let’s first look at a typical VPS solution. You have a VPS up and running on a single box and thus the unique IP would be bound to the box itself. It’s a fairly straightforward process.

Due to the nature of a cloud based infrastructure however, things are understandably a little more complicated. The application itself is no longer tied to one specific box. This means the application can dynamically be spawned on the best possible box, or on multiple boxes for that matter.

Another key difference is that due to the emphasis placed on performance in a true cloud based infrastructure, unique IP-based SSL solutions are terminated at hardware-based load balancers instead of the servers themselves. From that point, the connection from the load balancers to the web server(s) occurs over regular HTTP as this connection is within the confines of our network. This results in the .NET libraries not seeing the connection as secure.

To address this, the F5 load balancers will inject HTTP_X_FORWARDED_PROTO into the HTTP header as they pass the traffic along to the servers. Doing so allows us as developers to verify that the connection indeed originated via HTTPS. For performance reasons, this is the preferred method of configuration for larger cloud providers as well as large enterprises and  dot coms.

EL_blog_img_https

So let’s look at some of the implications and how we can resolve some of the key issues this creates.

First off, while we are working on automating this process, as I am writing this, you will need to open a ticket with the support department to have the F5’s configured to update the HTTP header.

If you have a webforms app and your goal is to simply to redirect HTTP to HTTPS via a rewrite in your web.config, you’ll want to use this rule:

<rewrite>
  <rules>
    <rule name="Redirect to HTTPS" stopProcessing="true">
      <match url="(.*)" />
      <conditions>
        <add input="{HTTP_X_FORWARDED_PROTO}" pattern="https" ignoreCase="true" negate="true" />
      </conditions>
      <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" />
    </rule>
  </rules>
</rewrite>

If you’re using MVC however, consider the following two points as I think they would affect most applications:

1) In order to use the [RequireHttps] attribute in our MVC projects, we need to override the OnAuthorization method of the RequireHttpsAttributeBase class, as in the example below:

using System;
using System.Web.Mvc;
using RequireHttpsAttributeBase = System.Web.Mvc.RequireHttpsAttribute;

namespace SslTest
{
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true,
		AllowMultiple = false)]
	public class RequireHttpsAttribute : RequireHttpsAttributeBase
	{
		public override void OnAuthorization(AuthorizationContext filterContext)
		{
			if (filterContext == null)
			{
				throw new ArgumentNullException("filterContext");
			}

			if (filterContext.HttpContext.Request.IsSecureConnection)
			{
				return;
			}

			if (string.Equals(filterContext.HttpContext.Request.Headers["X-Forwarded-Proto"],
				"https",
				StringComparison.InvariantCultureIgnoreCase))
			{
				return;
			}

			if (filterContext.HttpContext.Request.IsLocal)
			{
				return;
			}

			HandleNonHttpsRequest(filterContext);
		}
	}
}

2) Remember the HttpContext object is unaware that the connection is secure. Thus the property HttpContext.Request.IsSecureConnection will always return false. So instead of  using something like:

            if (HttpContext.Request.IsSecureConnection)
            {
                ViewBag.Message = "Verified Secure";
            }

Inspect the headers collection instead with something like the following:


            if (String.Equals(HttpContext.Request.Headers["X-Forwarded-Proto"], "https", StringComparison.OrdinalIgnoreCase))
            {
                ViewBag.Message = "Verified Secure";
            }

That should be enough to get you started. As always, we welcome your feedback! Let us know about your custom solutions.


2 Responses
  • Amador Reply

    I would like to know if the instructions are still valid since you mention that you were working to automate things at the time. I have just moved a site to everleap. It works well, the same as on the other host, on your alternate address which is using sni ssl. However, on our IP based certificate, it’s leading to an infinite loop

  • Michael Ossou Reply

    This has not been automated yet. I would need some more details before I could give you any guidance. The best place would be forum.everleap.com

    The more details you can share about your application, the issue, etc the more better.

Leave a Reply