HTTPS security best practices

HTTPS is essential to secure your site. But there are still many pitfalls you need to avoid

Author's image
Tamás Sallai
7 mins

The #1 HTTPS tip

The single most important tip regarding HTTPS is to use it. It really should be a no-brainer, and as browsers (and search engines!) are moving to discriminate non-encrypted websites, the incentive is even bigger. If you don't use HTTPS yet, look up Let's Encrypt and start using it.

No mixed content

Mixed content is when your site is available via HTTPS, but uses some resources that are loaded via HTTP. It's easy to check your site for mixed content: the browser makes it very clear that something is wrong.

This usually happens when you hardcode http:// URLs, then migrate your site to HTTPS. In this case, there are no problems before the migration, as the contents go unencrypted, but results in mixed content after.

Use https:// URLs in the first place if they are available, or just leave the scheme out and use //. That instructs the browser to use the same scheme as the page, i.e., http:// for HTTP, and https:// for HTTPS.

Check HTTPS config

HTTPS is not something with a binary state, so it's not enough to just turn it on. There are many configuration options that affect various aspects of the encryption itself.

Fortunately, there are some sites that test your config and provide recommendations how to fix some problems. One such is SSL Server Test from Qualys, which runs a robust set of checks.

Be sure to check out your HTTPS config from time to time, as new vulnerabilities and best practices can emerge.

Check HTTP headers

There are also several HTTP headers that control aspects with security implications. While not all of them are related to HTTPS, several are.

One site you can use to check yours is the Security Headers, which offers descriptions why a particular header would be important.

Get notified on new certificates

A recent addition to the certificate issuance process is the so-called Certificate Transparency. It means that whenever a certificate is issued for a domain, it must be submitted to a public log. In effect, you can see all the certs for your domain.

The best part is that you can even subscribe to notifications and get an email when a new certificate is issued. Again, there are several such services available, for example, there is one from Facebook

What to do with HTTP

A common misconception is that if you don't use HTTP for anything but to redirect to HTTPS, then you are secured. But if an adversary intercepts that initial HTTP request and can modify it, he can serve mailicious content instead of the redirect. Therefore, the first request is still vulnerable.

There are headers that can mitigate this, and we'll cover them too. But first, let's focus on the case when they are not used.

If an attacker can modify the request, then there is little you can do (apart from HSTS). But usually it's more likely he can read it but not modify it. To prevent an attack when an attacker can listen in to the traffic, there are a few best practices.

Send only the redirect

When you redirect to HTTPS, don't send any content along with the redirect. Any text you send is sent in plain text, so it's best to minimize it. Sending the content plus the redirect (for example, the home page) is no good.

Use secure cookies

Any cookie that is not marked as secure will be sent via HTTP as well as HTTPS. That, in turn, is something an attacker can use to impersonate the user on the HTTPS site.

Make sure you use secure cookies.

Should you use HTTP?

Yes, most of the time. The browsers, by default, request the HTTP site first, so you need to support that.

There is an exception though. If you have an API endpoint, then you can (and should) disable HTTP altogether. Why? Browsers follow redirects, but API clients might not, or might redirect a POST as a GET. You don't want some clients to work and some don't.

Also, for API clients, you provide the scheme by hand, so any consumer can use HTTPS only.

HSTS

Well, considering the things described above, it paints a worrysome picture. No matter what you do, the first request will be vulnerable. Fortunately, the HSTS header (HTTP Strict Transport Security) aims to remedy this.

It works by indicating that the browser should not use HTTP in subsequent requests but only HTTPS.

This is done using a response header on the HTTPS response:

Strict-Transport-Security: max-age=604800;

In effect, return visitors will be protected even if they try to load the site via HTTP.

max-age

This part controls how long the header is effective. After this time, the browser will forget the header and request the HTTP site again. It is renewed every time the user visits the page. It is there to provide an escape hatch in case you want to roll back HTTPS.

604800 is a week. If you use this, regular visitors will be protected continuously.

2592000 is one month.

31536000 is a year. You shouldn't use more than this. It's long enough, and for example, Chrome caps it to one year, so there is no point setting it any longer.

includeSubDomains

If you specify it, subdomains will be protected too. For example, if you send the header for example.com:

Strict-Transport-Security: max-age=604800; includeSubDomains

Then it will be effective for example.com, www.example.com, secure.example.com, www.secure.example.com, and all the other subdomains.

Should you use it?

Well, it depends. It seems like a great thing, but can cause problems.

For example, http://sub.example.com may work for some users but not for others, depending whether they have visited example.com before. A user who got the HSTS header will request only the HTTPS site, while others will happily fetch the HTTP one. If this subdomain does not support HTTPS, it makes a difference.

Also keep in mind that if you set it for a domain, you lose the ability to not support HTTPS for all subdomains. Your only escape plan is to wait for the header to expire, but that might take a long time.

preload

The problem with HSTS is that it only protects returning visitors, but the very first request will still be vulnerable.

There is a list of domains that browsers know to serve the HSTS header without visiting them first. Google maintains such a preload list, that is included in Chrome and other browsers.

This built-in preload list solves the problem with the first request, as if your site is on that list, the browser does not even try to fetch it via HTTP.

To get on the list, you need to send the HSTS header:

  • on the root domain
  • with a max-age of at least a year
  • with includeSubDomains
  • and with preload
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

This solves a particularly hard problem, but you need to excercise caution. Getting removed from the preload list is non-trivial, and you still need to wait for the header to expire (1 year!).

On the other hand, setting up HTTPS is not that hard, and services like Let's Encrypt make it easier.

You should opt in, but in small increments.

Tips on preloading

  1. Use a small max-age and work your way up

    1 week should be more than enough for a start. Run your site for some time and increase it to 2 weeks, then a month, then several months. When you reach 1 year, add preload.

  2. Use includeSubDomains

    Enforce HTTPS on subdomains early on, and check all the domains.

  3. Don't disable HTTP redirection

    Even if you get on the preload list, you still can not disable HTTP. Browsers that don't support HSTS or the preload list will still try to load your site via HTTP by default. Those would stop working if you disable it.

August 21, 2018