CSP and GA/GTM
Setting up Google Analytics with CSP
How Google Analytics Works
Google Analytics works by loading several scripts and making requests to Google's servers to track user behavior. The main challenges when implementing GA with CSP are:- Loading the initial analytics.js or gtag.js script
- Allowing connections to Google's data collection endpoints
- Handling dynamically injected scripts and inline scripts
Using Nonce or Hashes
There are two approaches to allow Google Analytics scripts with CSP:- Using nonces (recommended)
- Using hashes (requires more maintenance)
CSP Configuration for Google Analytics
Basic CSP configuration for Google Analytics
Content-Security-Policy:
script-src 'nonce-{random_nonce}' 'strict-dynamic' https://www.googletagmanager.com https://www.google-analytics.com;
connect-src https://www.google-analytics.com https://analytics.google.com;
img-src https://www.google-analytics.com;
Monitoring
Enable CSP reporting to monitor any blocked resources. This will help you identify any missing directives needed for Google Analytics.
Setting up Google Tag Manager with CSP
Understanding Google Tag Manager
Google Tag Manager is more complex than GA because it can dynamically load various scripts and tags. This requires a different approach to CSP configuration.Why Nonce is Mandatory for GTM
Using nonces with 'strict-dynamic' is the recommended approach for GTM because:- It automatically trusts scripts loaded by trusted (nonced) scripts
- Eliminates the need to maintain hash lists
- Handles dynamically injected scripts properly
CSP Configuration for Google Tag Manager
Basic CSP configuration for Google Tag Manager
Content-Security-Policy:
script-src 'nonce-{random_nonce}';
img-src www.googletagmanager.com;
connect-src www.googletagmanager.com;
Implementing GTM with Nonce
Here's how to implement GTM in a Next.js application:Implementing GTM with Nonce, use this script in your layout after getting the nonce (server side)
<script nonce={nonce} dangerouslySetInnerHTML={{
__html: `(function(w,d,s,l,i){
w[l]=w[l]||[];
w[l].push({
'gtm.start': new Date().getTime(),
event:'gtm.js'
});
var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),
dl=l!='dataLayer'?'&l='+l:'';
j.async=true;
j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX');`
}} />
Global Variables
Warning: Avoid using global variables in GTM scripts, as this may require 'unsafe-eval' in your CSP.
Monitoring
Enable CSP reporting to monitor any blocked resources. This will help you identify any missing directives needed for Google Analytics.
Full Example with Nonce Implementation
Here's a complete example combining both GA and GTM:Full Example with Nonce Implementation
Content-Security-Policy:
default-src 'self';
script-src 'nonce-${nonce}' 'strict-dynamic';
connect-src https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com;
img-src https://*.google-analytics.com https://*.googletagmanager.com;
frame-src https://*.google.com;
style-src 'self' 'unsafe-inline';
Conclusion
Implementing Google Analytics and Google Tag Manager with CSP requires careful configuration, but using nonces with 'strict-dynamic' provides the best balance of security and functionality. Remember to:
- Always use CSP reporting to monitor for blocked resources
- Implement nonce generation and rotation
- Avoid using global variables in GTM scripts
- Regularly review and update your CSP configuration