Google analytics.js and Content Security Policy

13.5k views Asked by At

I have a web app using the default html5boilerplate Content Security Policy.

However, we have the new Google analytics.js snippet on the page, which is being blocked by the CSP.

I've been trying to find an example of a CSP and JS include structure that will allow Google analytics.js, but haven't had any luck.

The closest SO post is Google Analytics and Content-Security-Policy header, but this is using the older ga.js.

Unfortunately the Google Docs don't mention CSP.

I've reached the following solution though:

Bottom of my html file:

<script type="text/javascript" src="/js/analytics.js"></script>

Content of analytics.js:

(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', 'UA-XXXXXXXX-1', 'auto');
ga('send', 'pageview');

.htaccess CSP:

Header set Content-Security-Policy "script-src 'self' https://ssl.google-analytics.com http://www.google-analytics.com; object-src 'self'"

This works - but I'm unsure if I will have broken the asyncronous nature of the GA code, or caused some other unintended consequence.

Can someone advise the correct way to allow Google analytics.js through a Content Security Policy?

Author Edit: In the end I used the solution detailed in Google Analytics and Content-Security-Policy header, reverting back to ga.js. But I'd still like to know if it's possible to use analytics.js in the same way.

Author Edit 2: Looks like it may be possible using analytics.js direct from Google and the same principles as the other SO post:

Bottom of HTML file:

<script type="text/javascript" src="https://ssl.google-analytics.com/analytics.js"></script>
<script type="text/javascript" src="/js/analytics.js"></script>

Contents of analytics.js:

ga('create', 'UA-XXXX-Y', 'auto');
ga('send', 'pageview');

CSP:

Header set Content-Security-Policy "script-src 'self' https://www.google-analytics.com https://ssl.google-analytics.com; object-src 'self'"

This is untested - I've not checked if Google analytics is receiving data, but there are no console or CSP errors. Fingers crossed.

3

There are 3 answers

0
john Smith On

your .htaccess solution should be all correct.

why should you brake the (clientside) asynchronous nature of it ?

in the browser console you will see which requests to which hosts are blocked, if there are any blocked request from gugl while surfing the page you can add the hostname to your policy-setting

0
Anbarasi U On

You seem to have CSP headers setup on your web app, where Google Analytics domains are not white-listed yet. All the requests that the client makes to external domains should be explicitly white-listed. (This is a good reference: https://hacks.mozilla.org/2016/02/implementing-content-security-policy/).

The CSP errors you see on the browser console are quite descriptive about what has to be white-listed in your CSP header.

For example, for this case,

Refused to load the image 'https://www.google.co.in/...' because it violates the following Content Security Policy directive: "img-src ".

this would solve the error:

img-src https://www.google.co.in <other-domains> 
0
quambo On

Using the alternate way described on https://developers.google.com/analytics/devguides/collection/analyticsjs/ helped. It is much like OP described in the second edit, you can either use a custom inline script that you apply a nonce on or outsource the inline script content into a seperate script, like OP suggested. Don't forget the async attribute on the script tag that references analytics.js.

Using this method, there will be no errors/warnings as no scripts are injected to your html.

Here is the relevant part from the link I posted:

Alternative async tracking snippet

While the JavaScript tracking snippet described above ensures the script will be loaded and executed asynchronously on all browsers, it has the disadvantage of not allowing modern browsers to preload the script.

The alternative async tracking snippet below adds support for preloading, which will provide a small performance boost on modern browsers, but can degrade to synchronous loading and execution on IE 9 and older mobile browsers that do not recognize the async script attribute. Only use this tracking snippet if your visitors primarily use modern browsers to access your site.

<!-- Google Analytics -->
<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>
<!-- End Google Analytics -->