Jump to the millipedia homepage
millipedia

Battling evil handbags

A lot of sites we look after are the target of hacking atempts; Sites dealing with race and immigration especially used to come under attack fairly often.

These days targeted attacks are much rarer but instead we have many automated scripts (mostly aimed at WordPress) which just have the aim of getting link spam included on a site.

So now, instead of battling idiot racists, we have to waste our time trying to stop people selling fake handbags - which is obviously better and yet somehow much more annoying.

This means we're always looking to keep up with best practice for security, so we now make sure we implement Content Security Policy (CSP) headers across our sites.

If you're not familiar with the purpose of CSP headers then there's several good articles that will explain how and why you should use them. This article by Scott Helme is a good introduction.

Essentially, what a CSP does is provide a whitelist of places from which a page on your website can load resources. If our evil handbag retailer tries to add a link that loads some nasty javascript from www.evil-handbags.com then our user's browser will recognise that it's not an authorised source and stop it from loading.

In most cases we can just added a directive to the head of our template that list the sources we trust. On some occasions though we want to be able to include some inline javascript on a page - perhaps from a module - and since we don't want to relax the rules to allow any old script to be added to our page we have to to take a slightly different tack and add a 'nonce'...

Skipping over the fact that British English 'nonce' can mean something altogether different, a nonce in this case is a one-time token that demonstrates our inline script is legitimate.

Our token is included in the CPS directive in the top of our page, and any script that doesn't have the right token will be blocked from running. The token is newly generated each time the page loads so can't be reused.

Creating the token

The CMS we use most often is CMS Made Simple, and in CMSMS we can easily add new snippets of code to extend the Smarty templating language the CMS uses.

In this case we created a simple plugin that generates a random string to use as our token. Saving the following code as function.millco_nonce.php in the assets/plugins directory of our CMSMS installation makes the function known the system:

function smarty_function_millco_nonce($params, &$smarty) {

    $nonce = base64_encode(random_bytes(20));
    if( isset($params['assign']) ){
            $smarty->assign(trim($params['assign']),$nonce);
            return;
    }else{
        return $nonce;
    }
}

We can then add a Smarty tag to the top of our page template which generates the nonce token and stores it as a variable we can use elsewhere in our templates.

    {$nonce="{millco_nonce}" scope=global}

We can include that variable in our CSP header. Here's the code we have on this site:

<meta http-equiv="Content-Security-Policy"
content="
    default-src  'self' https://www.youtube.com https://docs.google.com/ ;
    font-src 'self' https://fonts.gstatic.com;
    style-src 'self' https://fonts.googleapis.com 'unsafe-inline';
    script-src 'self'
        https://analytics.millipedia.com
        https://ajax.googleapis.com
        'nonce-{$nonce}' data:;
    img-src * data: ;
    ">

We can reuse that nonce in any inline script we want to add to our templates - our Piwik analytics code for example looks like this in the template:

    <!-- Piwik^h^h^h Matomo -->
    <script nonce="{$nonce}">

which ends up looking something like this once the template is built:

    <!-- Piwik^h^h^h Matomo -->
    <script nonce="cy9hCcVV2abfYwUlj/1NC69l4Lk=">

We could have put that in bit of javascript into a separate file served from a external trusted source of course but sometimes that's not covenient.

The nonce is different each time the page is loaded of course, so anyone wanting to inject an inline script isn't going to be able to reuse the code and if they can guess what it's going to be then, hell, maybe you should buy a handbag from them after all.

Update 12 Feb

Over the weekend a high profile example of how a CSP can protect your site cropped up.

Sites using an externally hosted script which provided a text to speech service discovered they were loading a script which caused visitors to their site to run a coin mining programme.

The sites loading this script included a range of government and public body sites including, rather embarrassingly, the Information Commissioners Office.

Now whilst a CSP would not have prevented loading the infected script in the first place (it was being loaded from a trusted site), that script then loaded the actual coin-mining code from another external site (coinhive.com). That site would not have been included in our CSP policy and so would have been prevented from running by the user's browser.

Security researcher Troy Hunt (who is always worth a read) has more information on this particular case over on his blog

Jan 23, 2018
in : CMSMS ,