You should be using SSL, it's free

You should be using SSL, it's free after all!

This post is how to get no-cost SSL solution (besides your time) for your website or API. I decided to create this post after the noble Dan Booth posted this tweet in reply to my assertion that everyone should use SSL:

It will definitely take time to configure SSL and to sort out mixed-content, etc. However if you use a reverse-proxy provider like CloudFlare, you don't have to worry about renewals or even buying the SSL. They provide that for absolutely free.

Disclaimer: Neither CloudFlare, Namecheap or Azure provide me any sort of compensation.

It's also a security mindset that we should all switch to: Never create a website without SSL.

So how do you do it?

I'll explain the process rather than provide detailed screenshots that will likely change over time. But I promise it's not that hard:

  1. Buy a domain (or use an existing) i.e. I buy my domains at Namecheap.com.
  2. Create a CloudFlare account.
  3. Add your website to your account (it'll tell you to change the nameservers in a wizard-like setup process).
  4. You'll want to create similar DNS records on your new CloudFlare account that are already on your existing DNS entries.
  5. Go to your domain provider (Namecheap) and point your nameservers to Cloudflare (they tell you what to type).
  6. It'll take up to 24 hours and provided you didn't goof up your new DNS records; users will never know that they are now proxying via CloudFlare (no down time). In reality it took about an hour for me. I kept pinging my domain from the command prompt and I started noticing the IP change.
  7. Start visiting your site via 'https'.
  8. If you haven't set up a custom domain at your hosting provider, you will also need to do that. I use this with Azure and don't pay their extra fees for SNI SSL, etc.

I realize that if you don't have any DNS chops, you might find this scary. To that I say ask a friend for help :)

 

I realize that if you don't have any DNS chops, you might find this scary. To that I say ask a friend for help :)

So what's the catch?

The catch is that you are sending all of your traffic to a third-party (CloudFlare) and then to your site. For me it is not a catch at all. If one of the properties I manage suffers a DoS attack, I can offer them quick DoS protection (though it's costly at CloudFlare). This isn't a post about CloudFlare, I don't care who you use. There is probably more out there.

There is one 'catch' for code that you should be aware of. When your traffic actually makes it to your hosting provider, you may notice that it arrives on port 80 (non-SSL). This may seem alarming. It's because the SSL connection is terminated at the load-balancer (at CloudFlare) and does not continue to traverse to the hosting provider over SSL.

If you have PCI or any other government compliance requirements, you should go full end-to-end SSL. If your site has zero SSL, you can at least get 95% SSL and you should do it.

Edit: There is a better explanation here about the termination of SSL. The traffic between CloudFlare and Azure (or whomever you're hosting with) is NOT encrypted. You can limit traffic to your provider to only accept connections from CloudFlare (not discussed here).

Edit: Troy Hunt talks about CloudFlare too and this is worth a read. TL;DR - Some SSL is better than no SSL. 

READ THIS PLEASE: After reading deeper into Troy Hunt's stuff, you can get full end-to-end SSL for free by doing some extra steps.

That said, in order to detect in code whether or not the user is using SSL becomes difficult (at first). In .NET you can try to look at the URL but it'll say 'http'. You can try to look at the properties designed for this like 'IsSecureConnection' or 'Scheme'. They will all say that you are not using SSL despite your browser saying otherwise.

What you need to do is look at a special header. Here is an example that works for me in WebApi:

 

using System.Linq;
using System.Net;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using Foo.Api.Exceptions;

namespace Foo.Api.Filters
{
    public class RequireSsl : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            //due to CloudFlare, we can't check the scheme, we have to literally check
            if (!actionContext.Request.RequestUri.AbsoluteUri.StartsWith("https:"))
            {
                //skip if local dev
                if (actionContext.Request.RequestUri.Host != "localhost")
                {
                    var forwardedProto = actionContext.Request.Headers.GetValues("X-Forwarded-Proto").ToList();

                    if (forwardedProto.All(x => x != "https"))
                    {
                        ExceptionHelper.Throw(HttpStatusCode.Forbidden, "You must use SSL!");
                    }
                }
            }
        }
    }
}

 

The header 'X-Forwarded-Proto' will have 'https' if it traversed the internet over SSL but was terminated once inside the destination network.

If you have code that auto-redirects the user on a website to use SSL and you get caught in an infinite-loop; make sure you look for the header and not check the standard ways to determine SSL status.

Summary

So that's it really. Once you do it the first time, you just do for every web propery. Use SSL please :)