Finding and fixing website security flaws

I recently discovered the website Observatory by Mozilla – a free tool to teach developers how to configure their sites safely and securely.

Using Observatory I scanned my site and got a security grade of D-.

Considering the grading goes from F to A+ getting the second lowest grade was a bit embarrassing… or so I thought. I checked some big brands to see how they are doing:

  • BBC (F)
  • Amazon (D)
  • Ebay (F)

Just seeing how poorly other sites perform makes you realise just how hard security can be. The good news is that knowing there is an issue is half the battle – now we can do something about it.

Finding security flaws

To get your security grade just add the site URL to Observatory’s homepage and hit ‘scan me’. A few seconds later you’ll get your results.

Observatory scan summary for bbc.co.uk - F grade

The security grading is calculated after completing 11 tests. The lowest score is zero and the highest is 135 out of 100 (which sounds odd but you get bonus points for doing really well). Your score is then used to give your site an overall grade from F to A+.

Each test has a different security value. For example if you don’t have a content security policy you will get -25 points but only -5 points for not implementing subresource integrity.

My site failed six tests, giving me a score of 25/100. My goal was to get 80/100 with a few hours of work.

Fixing the flaws

Some of the issues took seconds to resolve and others I still haven’t found the best solution without compromising website performance / functionality.

My site uses Apache for WordPress. All my fixes were applied to my .htaccess file.

I’ll discuss each problem separately and then share my updated .htaccess file so you can see the end result.

Content Security Policy

Content Security Policy (CSP) can prevent a wide range of cross-site scripting (XSS) and clickjacking attacks against your website.

Having a good content security policy is one of the most important factors to keep your site safe. Unfortunately it is also one of the hardest to implement.

A content security policy tells the browser what code, image or styling is allowed on your site. For example if you embed Youtube videos you need to add Youtube to your CSP.

Observatory gave my site -25 for not having a CSP.

WordPress and some of the plugins on my site add a lot of scripts and styles inline – especially in the admin section. To get all the WordPress functionality to continue to work I had to allow inline script and styles.

Having a CSP with inline scripts allowed changes my CSP score to -20. If I removed inline scripts I would get zero and my site would get an A+ grade.

Unfortunately I can’t do this at the moment without breaking key bits of functionality. I’m going to revisit this another day but having a CSP is better than not having a CSP.

This is my CSP but you can read how Mozilla implemented a CSP on their blog:

# CSP
Header set Content-Security-Policy "default-src 'none'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; img-src * 'self' secure.gravatar.com www.google-analytics.com; frame-src 'self' www.youtube.com; frame-ancestors 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ajax.googleapis.com/ajax/libs/webfont/ www.google-analytics.com s0.wp.com; connect-src 'self'; style-src 'self' 'unsafe-inline' fonts.googleapis.com"

X-Content-Type-Options

X-Content-Type-Options instructs browsers to not guess the MIME types of files that the web server is delivering.

To fix this I added the following to my .htaccess file.

Header set X-Content-Type-Options "nosniff"

X-Frame-Options

X-Frame-Options controls whether your site can be framed, protecting against clickjacking attacks. It has been superseded by Content Security Policy’s frame-ancestors directive, but should still be used for now.

To fix this I added the following to my .htaccess file.

Header set X-Frame-Options DENY

X-XSS-Protection

X-XSS-Protection protects against reflected cross-site scripting (XSS) attacks in IE and Chrome, but has been superseded by Content Security Policy. It can still be used to protect users of older web browsers.

To fix this I added the following to my .htaccess file.

Header set X-XSS-Protection "1; mode=block"

HTTP Strict Transport Security (HSTS)

HTTP Strict Transport Security (HSTS) instructs web browsers to visit your site only over HTTPS.

I had already set a HSTS but the max-age was too short to pass the test.

I changed my HSTS to:

Header set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

A word of warning before you add HSTS you need to make sure your site is using HTTPS. The change above also includes any subdomains you may have – if you don’t want this remove the reference ‘includeSubDomains; preload’.

Subresource Integrity

Subresource Integrity protects against JavaScript files and stylesheets stored on content delivery networks (CDNs) from being maliciously modified.

I decided not to fix this issue. In the time I had available and using WordPress there wasn’t a quick fix. It also only contributed to -5 points. You can find out more about subresource integrity on Mozilla’s site.

Updated .htaccess file

To combine all the fixes above I updated the .htaccess file to include.

# Add security headings
<IfModule mod_headers.c>
# CSP
Header set Content-Security-Policy "default-src 'none'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; img-src * 'self' secure.gravatar.com www.google-analytics.com; frame-src 'self' www.youtube.com; frame-ancestors 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ajax.googleapis.com/ajax/libs/webfont/ www.google-analytics.com s0.wp.com; connect-src 'self'; style-src 'self' 'unsafe-inline' fonts.googleapis.com"
# HSTS strict transport rule
Header set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# Turn on IE8-IE9 XSS prevention tools
Header set X-XSS-Protection "1; mode=block"
# prevent mime based attacks
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options DENY
</IfModule>

In a previous post I also discussed how to get https for free on your site and how to ensure a site resolves to https using .htaccess.

How to get free https using Let’s Encrypt

The final grade

After all my changes I changed my site from D- to B.

I made each change incrementally to test the impact on the site. Observatory shows your improvements over time to track your progress.

Observatory results changing from D- to B

Hopefully you can do better than me. But a word of warning, top marks doesn’t necessarily mean your site is 100% secure. Observatory only tests on a range of known issues such as cross-site scripting attacks and man-in-the-middle attacks. For example it doesn’t test for outdated software versions and SQL injection vulnerabilities.

Go test your site to see how you are doing and let me know how you go on.

Leave a Reply

Your email address will not be published. Required fields are marked *