/security

Securing your site on Cloudflare

I host my landing page (https://www.richardjameskendall.com) on AWS, but for performance and security reasons I've placed Cloudflare in front of it. I just use the free plan, but this is more than enough for my needs and it provides some great features including Cloudflare workers.

Cloudflare Workers

These are small pieces of serverless code which can run across ~190 data centres worldwide. You can have up to 30 for free + 100k free invocations per day of up to 10ms CPU time per invocation - that's a pretty chunky free allowance! You can use Javascript, Rust, C and C++.

You can attach these workers to your Cloudflare sites and modify aspects of the requests and responses very easily, for example you can add extra HTTP headers on the response.

This makes them perfect for my purpose, because I wanted to add some extra HTTP headers on my website to improve its security posture.

Checking your site

There are a couple of good services you can use to check the current status of your site and its security headers, those are

You can use these services to scan your site and report on common issues. Both guide you through various remedial actions you can take to resolve any warnings however I think Mozilla Observatory is the best for this. This service also invokes scans from other tools (like Qualsys SSL Labs) and aggregates all the results for you.

Example result from Mozilla Observatory

Building a Worker

Setup

Cloudflare makes a tool called Wrangler available for managing and deploying workers. You can install wrangler like this

npm install -g @cloudflare/wrangler

Note, if you have problems take a look here https://github.com/cloudflare/wrangler/issues/240.

Once installed you use wrangler config to set up your instance with access to your Cloudflare account (using an API key). The tool provides instructions on how to do this.

Create the worker

You can use the default Javascript template for this worker, in your termninal type

wrangler generate name-of-worker

This will create the empty project in the name-of-worker directory.

Inside the worker directory you will find a number of files, but the ones we will edit are wrangler.toml and index.js

wrangler.toml

This file will look like this:

name = "name-of-worker"
type = "javascript"
account_id = ""
workers_dev = true
route = ""
zone_id = ""

You should make the following edits:

Property Value
account_id Set this to your Cloudflare account ID, you can find this on any Overview page in the dashboard
zone_id Ser this to your domain's zone ID, you can find this on the Overview page for the domain you want to use
workers_dev You can set this to false as we don't need to deploy this to your workers dev subdomain
route Change this to match your website domain e.g. www.example.com

index.js

This is the file which contains the code which will be executed by Cloudflare for each request to your route. It gets responses from the origin and then edits the headers to add the extra headers needed to get a 'B' rating on the Obervatory service.

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  let response = await fetch(request)

  response = new Response(response.body, response)
  response.headers.set('Strict-Transport-Security', 'max-age=63072000')
  response.headers.set('X-Frame-Options', 'DENY')
  response.headers.set('X-Content-Type-Options', 'nosniff')
  response.headers.set('X-XSS-Protection', '1; mode=block')
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
  
  return response
}

Testing

It is really easy to test a worker. From the directory which contains your worker, issue this command:

wrangler preview --watch

This will open a browser session showing you a preview deployment of your worker and allow you to test it. --watch means that if you change your source code, wrangler will hot deploy the changes.

Cloudflare worker test screen

Clicking on the 'Testing' tab allows you to issue test requests which hit your worker, and you can inspect the output including the HTTP headers. You should be able to see new headers included in your output:

referrer-policy: strict-origin-when-cross-origin
strict-transport-security: max-age=63072000
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block

Deploying

To deploy your worker, issue the following command inside the directory which contains the worker:

wrangler publish

After this returns successfully your worker is live on your site and you'll see it in the Workers tab of the Cloudflare dashboard

Cloudflare dashboard with worker deployed

The result

Now we can see a much better result!

Observatory result following deployment

Next steps

In subsequent articles I'll cover:

  • environments and CI/CD for deploying workers automatically with GitHub actions
  • improving the score even more with Content Security Policies

-- Richard, Jan 2020