Securing a Static Site

Last updated 28 January, 2019

In the early days of the web static websites were the norm. Eventually dynamic sites appeared and was server side rendered because they had dynamic content supported by databases. In recent years we have seen that static site has become widely used again. And if you think about it this is common sense. Most sites don't need to dynamic load content from a database as the content doesn't change often enough.

The site you are reading this on right now is a static site hosted on Netlify. In this article I have put together a comprehensive guide on how to secure a static site.

Adding headers

Netlify has a easy way of adding headers to site, the only thing you need to do is adding a file called _headers to the root of your website.

A great tool to check if your site is secure is using Mozilla Observatory. This will give you a starting point on what you need to change.


Why do we need a Content Security Policy

Cross-Site Scripting (XSS) is the ability to inject scripts on a website and is one of the most commonly exploited vulnerabilities of the web.

Example You make a fancy new comment system, but you forget to strip HTML tags when a user enters a comment. A malicious attacker detects this and enters the following text line as a comment: <script src=""></script>

The attacker have now loaded a script that he is in control of on your website and can now do anything he wants. The example described is a typical scenario and has been the cause of many hacked sites over the years.

The Content Security Policy (CSP) is the best method we have of stopping XSS attacks. The CSP is a set of instructions sent to the browser that contains information on what resources the browser should be able to load, post form data to or other requests from the website.

The CSP can be delivered to the browser in a response header or in a meta tag in the HTML document.

Example Content-Security-Policy: script-src 'self'

This example tells the browser that it should only load script that is on the same origin (same host and port) as the website. If you have had this CSP the injected script in the comment system would never be loaded by browsers that support it.

In this article we will be using the response header option.

Enable reporting

Expect CT

Expect-CT: max-age=0, report-uri="https://{$subdomain}"

Expect-CT: enforce, max-age=30, report-uri="https://{$subdomain}"

Validate CSP

CSP is not enoug on it's own Most user agents now implements CSP, but not everyone.

HSTS Preload

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

Feature policy

Additional resources

Netlify documentation on adding headers