Tips and Tricks

An extra layer of security with HTTP response headers

We all use online services in our daily lives, for example for online shopping, filling out tax returns or checking health insurance. When we do, sensitive personal information is sent back and forth. That is why online security is so important. One easy way to increase the security of your website as a provider is to set up security headers.

An illustration of Semonto on a desktop background
Jelle Kalkman 8 September 2022

What are HTTP security headers?

Each time you load a website in your browser, your browser asks a server for the content. The server replies with the content but also includes additional metadata such as HTTP Headers. These headers are mainly instructions for the communication between a browser and a web server. However, some headers provide an extra layer of security by limiting the browser's behaviour.

You should review the response headers for all your websites and web applications especially if they handle sensitive information. The following security headers provide additional protection against session hijacking and other types of attacks:

  • Strict-Transport-Security (HSTS)
  • Content-Security-Policy (CSP)
  • X-Content-Type-Options
  • Permissions-Policy
  • Referrer-Policy
  • X-Frame-Options

Strict-Transport-Security (HSTS)

The HTTP Strict-Transport-Security header instructs the browser to only communicate with the web server using the secure HTTPS protocol and not the insecure HTTP protocol. This way you force the browser to use HTTPS.

When setting up this header, you must also supply a header directive, which is a specific setting. The max-age directive is a must, and two optional directives are includeSubDomains and preload.

  • The max-age directive specifies in seconds how long the browser must communicate with the server over HTTPS. The ideal setting for the max-age directive is 31536000, one year.
  • The includeSubDomains directive is to apply HSTS to all pages and subdomains. If the site has subdomains that also must be served over HTTPS, this directive is recommended.
  • The preload directive is a bit more elaborate and not standard. When this directive is set, you request the site to use an HSTS preload service. HSTS preloading is done by checking a list compiled by Google with sites that specify that HSTS policy is enforced. Browsers that use this list will always fetch sites from this list with HTTPS. If you are not sure about this, do not set this directive.

An example for this header is:
Strict-Transport-Security: max-age=31536000; includeSubDomains

Content-Security-Policy (CSP)

Browsers can load different types of resources such as fonts, styles, JavaScript or images. These resources can be served from the same domain as the site, inline in the HTML or loaded from another domain such as a CDN. To restrict where the resources are loaded from, whitelisted to be more precise, the Content-Security-Policy can be set. This is a countermeasure against, for example, cross-site scripting.

An example for this header is:
Content-Security-Policy: font-src 'self'; style-src 'unsafe-inline' 'self'; script-src 'unsafe-inline' 'unsafe-eval' 'self' https://js.sentry-cdn.com https://browser.sentry-cdn.com https://google.com https://googletagmanager.com https://google-analytics.com https://gstatic.com; img-src 'self' https://*.digitaloceanspaces.com https://google-analytics.com data:

The ‘self’ fetch directive in this example allows self-hosted styles, fonts, scripts and images in this example. The ‘unsafe-inline’ fetch directive allows the browser to use inline styles and JavaScript. Other allowed sources for JavaScript in this example are Google, DigitalOcean and Sentry.

When setting this header, you should always check if the site still works correctly. We noticed that for example, Google Analytics needs the ‘unsafe inline’ setting for JavaScript. The plugins inject JavaScript into the HTML DOM in order to work. Also 'unsafe-eval' might also be required by plugins. This is something we want to try to avoid because we feel this shouldn’t be used anymore.

X-Content-Type-Options

The X-Content-Type-Options header indicates that the specified MIME type must be followed by the browser. This can prevent MIME sniffing attacks. The only directive that can be set is nosniff.

An example for this header is:
x-content-type-options: nosniff

Permissions-Policy

The Permissions-Policy header controls which browser features can be used. This was first called Feature-Policy but has since been renamed. In this header, you can specify which browser features are allowed, such as location, full screen, autoplay and more. Some features are still under development and not yet supported by all browsers, and some browsers do not support this header altogether.

An example for this header is:
Permissions-Policy: autoplay=(self, "https://youtube.com"), encrypted-media=(self, "https://youtube.com"), fullscreen=(self, "https://youtube.com"), picture-in-picture=(self, "https://youtube.com")

This example allows autoplay, encrypted media, full-screen mode, and picture-in-picture mode for self-hosted videos and videos from YouTube.

Referrer-Policy

The Referrer-Policy header controls how much referrer information is sent to a page when a link is clicked. Values for this header are:

  • no-referrer
  • no-referrer-when-downgrade
  • same-origin
  • origin
  • strict-origin
  • origin-when-cross-origin
  • strict-origin-when-cross-origin
  • unsafe-url
  • an empty string

An example is:
Referrer-Policy: strict-origin-when-cross-origin

In this example, referrer information is not sent when the user clicks a link without the HTTPS protocol, and the current page is served with the HTTPS protocol. For all other possible values, check the docs.

X-Frame-Options

If you want to prevent that a site is placed inside an iframe, possibly on another website, you can set the X-Frame-Options header. This can prevent clickjacking attacks. There are two possible directives for this header, deny and sameorigin. The first directive prevents the page from being placed in an iframe altogether; the second only allows it if it has the same origin as the page.

For example:
X-Frame-Options: deny

How to set up response headers

The correct way to set up the response headers depends on your web server or hosting provider. When Apache is used, this is usually in the .htaccess file. Larger hosting providers often have their own way of setting them up. Netlify uses a _headers file, for example. Check the documentation from your web server or hosting provider. In most cases, this is not too difficult, and the documentation will be quite good. For example, the documentation from Netlify or Cloudflare. Geekflare also shared a post how to set up security headers for multiple web servers.

Checking security headers

One easy way to check the security headers for one of your web applications is to use this tool by Probely. You only need to supply the URL to have the tool check which response headers are set. If the tool finds any issues with your headers, you get links to documentation and guides on setting up the security headers.

After we set up the headers, we checked our website with this tool, and we received an A rating.

Screenshot of securityheaders.com

We repeated this process for all our other websites and API’s.

Conclusion

The security headers provide an easy way to increase security on your websites and web applications. The setup can be done quickly and provides you with extra insurance that your user's data are secured.

The OWASP Secure Headers Project provides great documentation on security headers and web application security in general. MDN also has very helpful docs. And finally, Scott Helme has some great posts with more in-depth information on security headers.

Besides setting up the security headers, you should also ensure that your TLS/SSL certificates are valid and didn’t expire. Check out our blog on SSL/TLS certificate monitoring.

No credit card required. Cancel anytime. No automatic renewal after the trial.

Like what you read?

Subscribe to our newsletter and get our next blog posts straight into your inbox.

Our privacy policy.