Content Security Policies – a whole new way of securing your website that no one knows about

Static and headless WordPress. In one click.

WordCamp Europe 2018 was in Belgrade, Serbia and I am honored to have been chosen to speak at the conference.

I am also glad it gave me a chance to visit Belgrade because I don’t think I would have gotten there otherwise.

What I loved about Belgrade was the fusion of old and new, East and West. I loved how you see buildings that were clearly some Communist dictator’s garish fantasy next to modern glass structures. The people were so friendly and I couldn’t help but see them as feisty: Belgrade has been destroyed 74 times throughout history, nations have fought over this place due to the waterways and their significance for commerce, and yet the people brush themselves off, get up, and rebuild – all with a positive outlook and a smile.

And here are some photos from the hall where I spoke:

What is a Content Security Policy (CSP)?

Content security policies (CSPs) are a relatively new security element on the web horizon. CSPs use browsers to detect and mitigate certain types of attacks like cross-site scripting (XSS), clickjacking and other code injection attacks resulting from execution of malicious content in the trusted web page context. CSPs can be used for simple purposes like enforcing HTTPS on SSL-enabled sites, to more sophisticated uses like authorizing only truly trusted sources and blocking others.

Most sites do not have CSPs installed, but it’s important to be aware of them and how they can be used to add an additional layer of security to your website.

Most web pages use third-party resources

Let’s start by looking at how the average web page loads in your browser. The web page accesses or calls different types of resources. Many of the resources are on your server but some of them are third-party services.

Here’s an example of third-party resources being called on a very well-known news site:

  • ‘//
  • //
  • //
  • //
  • //

How are websites compromised?

Websites are compromised either on the server side which is what we’re most familiar with – the vast majority of vulnerabilities and hacks happen on the server side. That’s when our sites get defaced or don’t work anymore.

The other way that sites get compromised is on the client side (the user in the browser). The most prevalent type of attack is Cross-site scripting (XSS). Cross-site scripting is when a hacker tries to inject their own script into your source code and have it loaded in the browser. It can originate on the server or client side. Once the attacker has this type of privilege it has the same privilege as your browser so it has access to your cookies, your web storage, and your DOM which is not good.

Three types of Cross-site scripting (XSS) attacks

Persistent XSS attacks are related to the server and originate in the database. One common example that used to be an issue was comment injection.

Reflected XSS attacks originate from the victim’s request. For example, someone gets a url in an email, and that url has parameters that loads a script and the victim thinks they’re clicking on a regular site and didn’t notice that the url wasn’t ok when they clicked on it.

DOM Based
DOM Based XSS attacks are a result of modifying the DOM in the victim’s browser used by the client side script to try to get certain types of information such as:

  • Cookie theft
  • Account takeover
  • Key logging
  • Displaying unwanted ads
  • Virus/malware infections
  • Redirecting traffic
  • Session hijacking
  • Stealing account credentials

A recent example of a XSS attack is the Browsealoud attack. Browsealoud is an accessibility browser add-on. The attackers got access to the library that these sites were calling and turned it into cryptomining tool and 5,000 sites were affected.
This is called cryptojacking, which can cause the following issues:

  • Slower devices
  • 100% CPU
  • High energy consumption
  • Battery drain
  • Overheating

Another example of an XSS attack was with the Animated Weather Widget Plugin, which was an innocent looking plugin that displays weather data on a WordPress site. The plugin developer didn’t realize that the source of the weather data was implementing cryptomining. So anyone using their service were cryptojacking their users. The plugin was removed from the WordPress plugins repository as a result.

We think we control our webpages but we don’t – we rely on a lot of third parties to generate our web pages.

So, how do we protect ourselves and our website visitors from third party attacks?

Hello Content Security Policy!

A Content Security Policy (CSP) lets you whitelist resources that you, as a site owner, want the browser to load for your webpage. Rather than trying to guess what potential bad resources are out there, you authorize trusted services.

A CSP is added to the header and tells the browser which scripts are ok to load, and which aren’t. For example, you might create a CSP that authorizes the browser to load Google scripts.

These CSPs will only take effect on browsers that support it and will just be ignored on browsers that don’t support it.

How to build a Content Security Policy

A CSP has two parts – directives and source expressions.

1. Directives are a list of types of assets that you can refer to such as:

  • font-src
  • frame-src
  • img-src
  • media-src
  • object-src
  • script-src
  • style-src

2. Source Expressions are patterns describing one or more trusted servers that scripts can be downloaded from including:

  • ‘none’
  • ‘self’
  • * (everything)
  • ‘unsafe-inline’
  • ‘unsafe-eval’

The point of CSP is to separate structure from behavior. Ideally, you shouldn’t be using inline scripts and styles, but if your site is built that way, you can create a CSP that allows them.

Here are some examples:
1. If you don’t specify any of the other directives, the default will be self and https:

Content-Security-Policy: default-src ‘self’ https:;

2. If you want to allow scripts from your own domain and Google Analytics:

Content-Security-Policy: script-src ‘self’

3. If you want to allow fonts from your server and Google fonts:

Content-Security-Policy: font-src ‘self’

4. If you never want objects to load:

Content-Security-Policy: object-src ‘none’

5. Here’s how to set your CSP if you want to load unsafe inline scripts.. even though they’re considered..unsafe 😉

Content-Security-Policy: script-src ”unsafe-inline’ ‘unsafe-eval’

One way to secure these ‘unsafe’ inline scripts is to add a nonce:

<script nonce=EDNnf03nceIOfn39fn3e9h3sdfa>
//inline code 

Content-Security-Policy: script-src ‘nonce- EDNnf03nceIOfn39fn3e9h3sdfa

Another way to secure these ‘unsafe’ inline scripts is with a hash. which checks if the script has been changed or uploaded, and if it has, then it won’t load.

<script>alert('Hello, world.');</script>

Content-Security-Policy: script-src ‘sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng=’

6. And here’s my favorite CSP. Are you ready?! Drumroll please…

Content-Security-Policy: upgrade-insecure-requests;

All of our sites should be running on HTTPS and SSL. However, during the implementation, you might miss an asset that’s running on HTTP. By adding this CSP, it tells the browser to always load every asset via HTTPS.

You’ll always have a green padlock and you’ll never have mixed content.

CSP in Report-only mode

Since adding a CSP is not so simple and can sometimes break things, instead of implementing your CSP and having it become active immediately, you can use the report-only function which lets you look in the developer console and see what is being blocked by the CSP if it were activated. Here’s the report-only mode CSP:

Content-Security-Policy-Report-Only: default-src ‘none’; script-src; report-uri /csp-reports

It can even send logs to a URL that you specify, in JSON format.

Subsource Integrity – SRI

SRI adds another layer of security to your site. It checks to see if a script was updated and compares the updated version with the hash. For example, if there’s a reference to example-framework.js and that script gets updated, then that hash is no longer relevant and SRI tells the browser not to load it. This is not great for scripts that get automatically updated but it would have prevented the Browseaware cryptojacking attack.

How to add a CSP to your site

1. On the server level as headers. This is the recommended way to implement a CSP

2. In functions.php, you can add CSP as follows:

add_action(‘send_headers’, function(){
// Prevent XSS Attack
header(“Content-Security-Policy: default-src ‘self’;”); })

3. Meta tags – you can use Meta tags to easily add a CSP, but it doesn’t support less common directives like frame-ancestors, report-uri, or sandbox
<meta http-equiv=”Content-Security-Policy” content=”default-src; child-src ‘none’; object-src ‘none'”>

Tools for your CSP Journey

Here are some tools to check if your content security policy are set up properly.

In your browser console, open the Network tab and click through to see the header information

KeyCDN header check

Google’s CSP Evaluator

Security headers

This one is our personal favorite. It shows you how your site is doing CSP-wise and gives you a letter grade.

For example, I tested the White House and they didn’t quite pass 😉 More on that below…

CSP Generator

Analyzes a page and tells you what to whitelist. The Mac version is not fully fleshed out

Here are some WordPress plugins that can help you with CSP:

If this is the first you’re hearing of CSP, you’re not alone.The adoption of CSP around the web was 2.4% in Feb 2018.

The point of CSP is not to prevent Cross-site scripting (XSS) but what it does do is give your site an added level of protection if your site is compromised.

An entertaining way to test if a site has a CSP active is a script that was created by Breno de Winter that you can add to the browser console tab. And if the site does NOT have a CSP, it plays the Harlem Shake. You can get the script here.


Here are some more useful resources

Although Content Security Policies are still relatively unknown, they will start becoming a standard security measure because it gives site owners and developers more control over the flow of third-party resources they otherwise can’t control. It’s important to do everything you can to can protect yourselves and your users.