Configuring Security Headers with Netlify

3 minute read

There is a set of standard HTTP headers that every website should implement to ensure a basic level of security. In this note, I’ll cover these headers and how to set them up for sites deployed on Netlify.

Common Security Headers

First, let’s review the basic HTTP headers — these are general for all requests and provide a foundational layer of security.

Content-Security-Policy Header

This helps protect your website from Cross Site Scripting attacs by providing a list of approved content. This header restricts the use of content that doesn’t comply with the rules or shouldn’t be part of your site’s content. Configuring this header can seem complex, so if you want to dive deeper, check the official site. Example usage:

Content-Security-Policy: default-src 'https://example.com'; script-src  'unsafe-inline' 'https://example.com'; style-src 'unsafe-inline' 'https://example.com'; object-src 'none'

X-Frame-Options Header

This tells the browser whether your site can be displayed in an iframe or not. In most cases, you’ll want to disallow this, as it prevents your site from being used for Clickjacking attacks. The concept is simple: a visitor sees your site’s page and clicks a button. In reality, there is another transparent page layered on top, and the visitor clicks a button on that page instead. Example usage:

X-Frame-Options: DENY

X-XSS-Protection Header

In older browsers (mainly Safari), this header protects your site from XSS attacs. Most browsers recognize this header and will stop loading the page when they detect such attacks. Example usage:

X-XSS-Protection: 1; mode=block

X-Content-Type-Options Header

This prevents the browser from analyzing and modifying the MIME type of the content. This type of attack checks the content stream to try and identify the file format inside and inject additional data. Example usage:

X-Content-Type-Options: nosniff

Referrer-Policy Header

This controls how much referrer information is sent when the browser accesses your site from another domain. Essentially, this header manages the amount of referrer data included in requests. Example usage:

Referrer-Policy: same-origin

Strict-Transport-Security Header

This protects your site from being redirected to unsecured protocols. It tells browsers to always connect to your site using HTTPS and never over HTTP. Example usage:

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

Permissions-Policy Header

This informs browsers about which features (e.g., geolocation, camera, microphone) are allowed or restricted on your website. Example usage:

Permissions-Policy: geolocation=(), gyroscope=(), magnetometer=()

Content-Security-Policy Header

Content Security Policy (CSP) is used to determine whether a content being loaded in the page is from a trusted source or not. CSP is versatile in controlling all different kinds of content from which script gets loaded to what a form target can be set to through its various directives, and hence protects your users from a wide range of attacks such as clickjacking attacks and cross-site scripting attacks. Example usage:

Content-Security-Policy: script-src 'self' www.googletagmanager.com;

Setting Up Headers in Netlify

There are two ways to set headers in Netlify: by adding them to the Netlify configuration file (netlify.toml):

[[headers]]
  for = '/*'

  [headers.values]
    X-Frame-Options = 'DENY'
    X-XSS-Protection = '1; mode=block'
    X-Content-Type-Options = 'nosniff'
    Referrer-Policy = 'same-origin'

    Permissions-Policy = '''
    accelerometer=(),
    camera=(),
    geolocation=(),
    gyroscope=(),
    magnetometer=(),
    microphone=(),
    payment=(),
    usb=(),
    interest-cohort=()
    '''

    Content-Security-Policy = """
    script-src 'self';
    form-action 'none'
    """

    Strict-Transport-Security = '''
    max-age=31536000;
    includeSubDomains;
    preload
    '''

or by using a separate _headers file:

/*
  X-Frame-Options = "DENY"
  X-XSS-Protection = "1; mode=block"
  X-Content-Type-Options = "nosniff"
  Referrer-Policy = "same-origin"
  Content-Security-Policy = "script-src 'self'; form-action 'none'"
  Permissions-Policy = "accelerometer=(), camera=()"
  Permissions-Policy = "geolocation=(), gyroscope=()"
  Permissions-Policy = "magnetometer=(), microphone=()"
  Permissions-Policy = "payment=(), usb=(), interest-cohort=()"
  Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"

Note: Netlify supports repetitions within the _headers file. For instance, the following example:

/path
  example: one
  example: two

Will behave the same as:

/path
  example: one, two

Conclusion

Setting security headers should give your website an “A” rating on services like securityheaders.com, and using them wisely will make security testers respect your site’s level of protection.

Configuring a Content Security Policy depends on the specific website and can vary, for instance, if you use Google Analytics or other third-party scripts. Keep in mind that when implementing any security policy, you should thoroughly test your site to ensure that all third-party resources and clients still function correctly.

References