hero banner

SSL Termination and ASP.NET

This seems to hit everyone as they start out using SSL Termination and ASP.NET..

When you have a website running on a server with an SSL certificate installed, HttpRequestBase has a public property you can access as Request.IsSecureConnection that happily tells you if you’re running over SSL or not. This is useful when you need to generate full canonical URIs (for outbound links or return URIs) that include the scheme.

As your business matures and you scale out, maintaining SSL certificates across your IIS cluster becomes a headache, and many people opt to use SSL Termination – installing the SSL certificate only on a load balancer or reverse proxy. The reverse proxy then deals with the SSL encryption and decryption of traffic, forwarding the traffic, unencrypted, to the origin webserver.

So you take your code, that was generating URIs, and move to an SSL terminated environment and your code breaks. The URIs all get generated wrong, and you’re not sure what’s going on. You crack open the codebase on your local dev machine, with your self signed debug certificate and run a few tests – everything works. This is because on your local dev environment, you’re not SSL terminated, and on your staging and production environments, you are – you’re not going crazy, there isn’t any SSL here.

And you still need to generate valid URIs.

Supporting this scenario

There’s a non-standardised convention based header that a lot of terminating load balancers add to the HTTP headers of your request when they encrypt and decrypt your traffic – “X-Forwarded-Proto” which will be set to “https” if your load balancer has modified the scheme of your traffic. Hopefully your load balancer will add it, or support you adding it as a rule or configuration setting.

Request.IsSecureConnection is false in this scenario, and should always be false.- after all, the connection between your server and your load balancer is insecure, and Microsoft should resist the urge to change the meaning of this flag, so you’re going to want to support it another way.

So do the simplest thing that should possibly work, here are some extension methods:

using System;
using System.Linq;
using System.Web;

public static class SslTerminationExtensions
{
    public static bool IsSecureOrTerminatedSecureConnection(this HttpRequestBase request)
    {
        if (!request.IsSslTerminated())
        {
            return request.IsSecureConnection;
        }

        var header = request.Headers["X-Forwarded-Proto"];
        return string.Equals(header, "https", StringComparison.OrdinalIgnoreCase);
    }

    public static bool IsSslTerminated(this HttpRequestBase request)
    {
        return request.Headers.AllKeys.Contains("X-Forwarded-Proto");
    }
}

This will allow you to change any calls to Request.IsSecureConnection for calls to Request.IsSecureOrTerminatedSecureConnection() and your code will work correctly in both your self-signed dev environment, and your SSL terminated dev and QA environments.

3 Responses to “SSL Termination and ASP.NET”

  1. DalSoft Says:

    Probably worth pointing out that SSL termination is less of an issue on a modern stack. SSL termination was originally designed to remove the encryption overhead from the web server onto the load balancer.

    Today’s servers can handle encryption with next to zero overhead. SSL certificates can easily be scripted as part of your continuous deployment pipeline.

    I would avoid the extra complexity that SSL Termination adds – you can also avoid expensive load balancers if you don’t have this as an requirement.

  2. david Says:

    @DalSoft – entirely agree – with sufficient automation, the cons of SSL termination rapidly outweigh the pros.

  3. John L Says:

    The Pros: SSL termination at the load balancer allows installing one certificate without any dependencies on scripting so I believe this to be a simpler approach. In addition, having traffic un-ecrypted between the LB and the back end nodes allows for an IDS to scan traffic for malicious requests. This just can’t be done when terminating at the web servers.

    The Cons: Since backend traffic is all over HTTP, setting cookies secure becomes an issue since the stack knows the connection is over HTTP and will refuse to set them. For my workaround example I’ll simplify / modify Davids example:

    public static bool IsSecureOrTerminatedSecureConnection(this HttpRequestBase request)
    {
    if (Request.Headers["X-Forwarded-Proto"] == “https”)
    Request.ServerVariables["HTTPS"] = “on”;

    return Request.IsSecureConnection;
    }

Leave a Reply