Decided to do some security hardening of my blog as an exercise, thought I would share the results.

I started with a big fat F :)
Report from: securityheaders.io

Content Security Policy

Content security policy defines what resources your site can access, if you want details look at this, thats covers the why and how pretty well so I wont repeat it.

First thing I want to do is setup a policy that just reports errors to me, I can then browse my site and see what would be broken. If you have a larger site, you could use a crawler to see whats broken and the report-uri option to collect the reports.

Lets try only allowing self (same origin)

Content-Security-Policy-Report-Only: default-src 'self'  

Once added to my nginx config and I visit my blog, I see that there is a warning:

[Report Only] Refused to execute inline script because it violates the following Content Security Policy directive: "default-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-XoyBaAkHyQQlHsSXXKv7iO5NDpyGkOYEAIGX7tm+YfI='), or a nonce ('nonce-...') is required to enable inline execution. Note also that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.

So my options here are to either enable inline execution of JS/CSS, add a SHA hash to the header, or add a nonce to the header and tag. As the inline script was just to bootstrap the jquery mobile menu, I decided to just move it into a file and the warning was fixed. That was pretty much it for my blog, however checking Ghosts admin UI there are 500+ warnings :) They are mainly fonts and inline CSS warnings. After a bit of trail and error I finally came up with the following rule:

Content-Security-Policy-Report-Only: default-src 'self' 'unsafe-inline'; font-src 'self' fonts.googleapis.com fonts.gstatic.com; style-src 'self' 'unsafe-inline'  fonts.googleapis.com; img-src 'self' s3.amazonaws.com  

Quite a beast, I only applied this to the admin so the public blog was as locked down as possible. I will see if I can reduce that down later on.

After removing Report-Only and re-running the test I now have a D!

My verdict on CSP, well its great and all but for anything complex I can see this being very hard to maintain and if you want ads, well best think again. Hopefully this will mature in the future, being able to lockdown things is very useful, just needs a little more flexibility.

X-Frame Options

Next up is X-Frame Options, this is actually deprecated now as CSP replaces it but we still include it because its browser support is better (for now).

For my blog this one is easy:

X-Frame-Options: DENY  

I don't need to iframe my site at all so its an easy choice.

And now I have a C:

XSS Protection

Next up XSS protection, this one is super simple and just enables the browsers protection to block things that trigger the protection.

X-Xss-Protection: 1; mode=block  

And that gets us an A:

X-Content-Type Options

Finally we have X-Content-Type-Options, this stops the browser from sniffing mime types and relies on known types of the server.

X-Content-Type-Options: nosniff  

And my final score A+:

But wait! What about SSL, my site doesn't have a cert, lets give Lets Encrypt a go.

SSL

So it took about 30 minutes to setup auto-renewing Lets Encrypt cert, very easy I am impressed!

After that its time to check my SSL config, running the headers test again I get a B:

Strict Transport Security

This helps stop MITM attacks and is super simple, its a shame banks don't use this!

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

Easy enough and now we are back to an A:

Key Pinning

I have decided to come back to key pinning as it requires a bit more reading than Saturday afternoon offers :)

So my final score is an A which is much better than the F to start with :)

There is one last check to do though:

https://www.ssllabs.com/ssltest/analyze.html?d=thepopeisdead.com

This site checks your SSL setup and flags any potential problems.

So I get a B, and a warning about DH key exchange being weak, lets try and fix that...

The fix was basically to follow the instructions here: https://weakdh.org/sysadmin.html which involves generating a new DH key and making Nginx use that instead of the weaker 1024 default one.

This gives me an A+ score!

And thats it, an A and an A+ not bad for a Saturday afternoons work.