CSP and Templates

silverstripe-4
Tags: #<Tag:0x00007f10cc899f20>

#1

Silverstripe Version:
Silverstripe 4

Question:
My organisation is currently trying to deploy content security policies (CSP) Content Security Policy (CSP) - HTTP | MDN

One of the organisations requirements is to remove the script-src ‘unsafe-inline’

We use one Silverstripe template for multiple websites and many config options are stored in the siteconfig to allow each site to have different options but follow our same templates

I’ve edited our templates and have moved most of the inline scripts out into .js files and required them as normal in ss templates.

This has worked for 90% however some ss templates call variables from the siteconfig to generate the javascript so I cannot move these out to static .js files

is there any way to create a ss file that is built to a .js file and stored in /javascript folder?
I know i can hard code multiple .js files and then only require the correct one but this wont work in all cases and seams like a fudge.

bellow is an example of a .ss file that is included on every page template


&lt;% if $SiteConfig.GoogleAnalyticsUA %&gt;
&lt;script&gt;

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '{$SiteConfig.GoogleAnalyticsUA}', 'auto');
ga('require', 'displayfeatures');
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');

&lt;/script&gt;
&lt;% end_if %&gt;

Thanks,


#2

Seems like it’s the sort of thing you could be using javascript templates for. You can keep the logic in your controller then, and it hopefully will all be nice and neat:

https://docs.silverstripe.org/en/4/developer_guides/templates/requirements/#javascript-files


#3

Perfect, had no idea you could do that thanks that will work.

For anyone else with this issue, you can also provide a hash of the script or a nonce to the CSP that allows your inline script to execute, but javascript templates looks way simpler to implement


#4

Im missing something still…

so Requirements::javascriptTemplate works perfectly to take my siteconfig and merge into templated javascript, but the javascript is added to the dom as inline javascript not as a file reference so still break csp

I cant see any way to get Requirements to insert as a reference not inline.

Ive tried combining the JS using Requirements::combine_files which does insert correctly but then the combined files don’t template so you get all the variable references not the values.

what am i doing wrong :frowning:


#5

although the javascript templates recommended by @DorsetDigital provided a solution for putting the variables into the javascript, I could not figure out a way to then add the javascript to the dom as a file reference instead of inline script.

as a result the CSP was still blocking it as it was unsafe-inline script.

my solution incase anyone else has the same issue was to generate a random nonce in the page controller

$rg = new RandomGenerator();
$this->nonce = $rg->randomToken(‘sha256’);

then add a new meta tag at the top of my head template

meta http-equiv=“Content-Security-Policy” content=“script-src ‘self’ ‘nonce-$nonce’”

then in each of my .ss files where i reference inline script i could call the script with

script type=“text/javascript” nonce=$nonce

it feels like a messy solution but it appears to work fine.