After playing around with this for quite some time I am still searching for a solution. The content Security Policy of a certain website requires a long list of allowed sources (especially because Google loads certain content with dynamic .TLDs - Google states in the documentation also that this is necessary for some services: https://developers.google.com/tag-platform/tag-manager/web/csp?hl=de).
The better solution for CSP is to put it into a header, but unfortunately a very large header causes issues with servers and clients.
Just have a look at the policy:
default-src 'self' https://*.sentry-cdn.com https://*.ingest.sentry.io https://*.sampleassets.com https://*.stripe.com https://cdn.rawgit.com https://cdn.jsdelivr.net https://www.google.com https://www.google-analytics.com https://www.gstatic.com https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/ https://www.googletagmanager.com https://*.doubleclick.net https://project.dev https://*.project.dev https://project.dev; script-src 'unsafe-inline' https: 'strict-dynamic' 'nonce-xxx' *.sentry-cdn.com https://www.google.com https://www.google-analytics.com https://www.gstatic.com https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/ https://www.googletagmanager.com https://*.doubleclick.net https://*.google.com/ https://*.google.ad/ https://*.google.ae/ https://*.google.com.af/ https://*.google.com.ag/ https://*.google.com.ai/ https://*.google.al/ https://*.google.am/ https://*.google.co.ao/ https://*.google.com.ar/ https://*.google.as/ https://*.google.at/ https://*.google.com.au/ https://*.google.az/ https://*.google.ba/ https://*.google.com.bd/ https://*.google.be/ https://*.google.bf/ https://*.google.bg/ https://*.google.com.bh/ https://*.google.bi/ https://*.google.bj/ https://*.google.com.bn/ https://*.google.com.bo/ https://*.google.com.br/ https://*.google.bs/ https://*.google.bt/ https://*.google.co.bw/ https://*.google.by/ https://*.google.com.bz/ https://*.google.ca/ https://*.google.cd/ https://*.google.cf/ https://*.google.cg/ https://*.google.ch/ https://*.google.ci/ https://*.google.co.ck/ https://*.google.cl/ https://*.google.cm/ https://*.google.cn/ https://*.google.com.co/ https://*.google.co.cr/ https://*.google.com.cu/ https://*.google.cv/ https://*.google.com.cy/ https://*.google.cz/ https://*.google.de/ https://*.google.dj/ https://*.google.dk/ https://*.google.dm/ https://*.google.com.do/ https://*.google.dz/ https://*.google.com.ec/ https://*.google.ee/ https://*.google.com.eg/ https://*.google.es/ https://*.google.com.et/ https://*.google.fi/ https://*.google.com.fj/ https://*.google.fm/ https://*.google.fr/ https://*.google.ga/ https://*.google.ge/ https://*.google.gg/ https://*.google.com.gh/ https://*.google.com.gi/ https://*.google.gl/ https://*.google.gm/ https://*.google.gr/ https://*.google.com.gt/ https://*.google.gy/ https://*.google.com.hk/ https://*.google.hn/ https://*.google.hr/ https://*.google.ht/ https://*.google.hu/ https://*.google.co.id/ https://*.google.ie/ https://*.google.co.il/ https://*.google.im/ https://*.google.co.in/ https://*.google.iq/ https://*.google.is/ https://*.google.it/ https://*.google.je/ https://*.google.com.jm/ https://*.google.jo/ https://*.google.co.jp/ https://*.google.co.ke/ https://*.google.com.kh/ https://*.google.ki/ https://*.google.kg/ https://*.google.co.kr/ https://*.google.com.kw/ https://*.google.kz/ https://*.google.la/ https://*.google.com.lb/ https://*.google.li/ https://*.google.lk/ https://*.google.co.ls/ https://*.google.lt/ https://*.google.lu/ https://*.google.lv/ https://*.google.com.ly/ https://*.google.co.ma/ https://*.google.md/ https://*.google.me/ https://*.google.mg/ https://*.google.mk/ https://*.google.ml/ https://*.google.com.mm/ https://*.google.mn/ https://*.google.ms/ https://*.google.com.mt/ https://*.google.mu/ https://*.google.mv/ https://*.google.mw/ https://*.google.com.mx/ https://*.google.com.my/ https://*.google.co.mz/ https://*.google.com.na/ https://*.google.com.ng/ https://*.google.com.ni/ https://*.google.ne/ https://*.google.nl/ https://*.google.no/ https://*.google.com.np/ https://*.google.nr/ https://*.google.nu/ https://*.google.co.nz/ https://*.google.com.om/ https://*.google.com.pa/ https://*.google.com.pe/ https://*.google.com.pg/ https://*.google.com.ph/ https://*.google.com.pk/ https://*.google.pl/ https://*.google.pn/ https://*.google.com.pr/ https://*.google.ps/ https://*.google.pt/ https://*.google.com.py/ https://*.google.com.qa/ https://*.google.ro/ https://*.google.ru/ https://*.google.rw/ https://*.google.com.sa/ https://*.google.com.sb/ https://*.google.sc/ https://*.google.se/ https://*.google.com.sg/ https://*.google.sh/ https://*.google.si/ https://*.google.sk/ https://*.google.com.sl/ https://*.google.sn/ https://*.google.so/ https://*.google.sm/ https://*.google.sr/ https://*.google.st/ https://*.google.com.sv/ https://*.google.td/ https://*.google.tg/ https://*.google.co.th/ https://*.google.com.tj/ https://*.google.tl/ https://*.google.tm/ https://*.google.tn/ https://*.google.to/ https://*.google.com.tr/ https://*.google.tt/ https://*.google.com.tw/ https://*.google.co.tz/ https://*.google.com.ua/ https://*.google.co.ug/ https://*.google.co.uk/ https://*.google.com.uy/ https://*.google.co.uz/ https://*.google.com.vc/ https://*.google.co.ve/ https://*.google.vg/ https://*.google.co.vi/ https://*.google.com.vn/ https://*.google.vu/ https://*.google.ws/ https://*.google.rs/ https://*.google.co.za/ https://*.google.co.zm/ https://*.google.co.zw/ https://*.google.cat/; img-src data: 'self' https://*.sentry-cdn.com https://*.ingest.sentry.io https://*.sampleassets.com https://*.stripe.com https://cdn.rawgit.com https://cdn.jsdelivr.net https://www.google.com https://www.google-analytics.com https://www.gstatic.com https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/ https://www.googletagmanager.com https://*.doubleclick.net https://project.dev https://*.project.dev https://project.dev https://*.s3.amazonaws.com https://www.google.com https://www.google-analytics.com https://www.gstatic.com https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/ https://www.googletagmanager.com https://*.doubleclick.net https://*.google.com/ https://*.google.ad/ https://*.google.ae/ https://*.google.com.af/ https://*.google.com.ag/ https://*.google.com.ai/ https://*.google.al/ https://*.google.am/ https://*.google.co.ao/ https://*.google.com.ar/ https://*.google.as/ https://*.google.at/ https://*.google.com.au/ https://*.google.az/ https://*.google.ba/ https://*.google.com.bd/ https://*.google.be/ https://*.google.bf/ https://*.google.bg/ https://*.google.com.bh/ https://*.google.bi/ https://*.google.bj/ https://*.google.com.bn/ https://*.google.com.bo/ https://*.google.com.br/ https://*.google.bs/ https://*.google.bt/ https://*.google.co.bw/ https://*.google.by/ https://*.google.com.bz/ https://*.google.ca/ https://*.google.cd/ https://*.google.cf/ https://*.google.cg/ https://*.google.ch/ https://*.google.ci/ https://*.google.co.ck/ https://*.google.cl/ https://*.google.cm/ https://*.google.cn/ https://*.google.com.co/ https://*.google.co.cr/ https://*.google.com.cu/ https://*.google.cv/ https://*.google.com.cy/ https://*.google.cz/ https://*.google.de/ https://*.google.dj/ https://*.google.dk/ https://*.google.dm/ https://*.google.com.do/ https://*.google.dz/ https://*.google.com.ec/ https://*.google.ee/ https://*.google.com.eg/ https://*.google.es/ https://*.google.com.et/ https://*.google.fi/ https://*.google.com.fj/ https://*.google.fm/ https://*.google.fr/ https://*.google.ga/ https://*.google.ge/ https://*.google.gg/ https://*.google.com.gh/ https://*.google.com.gi/ https://*.google.gl/ https://*.google.gm/ https://*.google.gr/ https://*.google.com.gt/ https://*.google.gy/ https://*.google.com.hk/ https://*.google.hn/ https://*.google.hr/ https://*.google.ht/ https://*.google.hu/ https://*.google.co.id/ https://*.google.ie/ https://*.google.co.il/ https://*.google.im/ https://*.google.co.in/ https://*.google.iq/ https://*.google.is/ https://*.google.it/ https://*.google.je/ https://*.google.com.jm/ https://*.google.jo/ https://*.google.co.jp/ https://*.google.co.ke/ https://*.google.com.kh/ https://*.google.ki/ https://*.google.kg/ https://*.google.co.kr/ https://*.google.com.kw/ https://*.google.kz/ https://*.google.la/ https://*.google.com.lb/ https://*.google.li/ https://*.google.lk/ https://*.google.co.ls/ https://*.google.lt/ https://*.google.lu/ https://*.google.lv/ https://*.google.com.ly/ https://*.google.co.ma/ https://*.google.md/ https://*.google.me/ https://*.google.mg/ https://*.google.mk/ https://*.google.ml/ https://*.google.com.mm/ https://*.google.mn/ https://*.google.ms/ https://*.google.com.mt/ https://*.google.mu/ https://*.google.mv/ https://*.google.mw/ https://*.google.com.mx/ https://*.google.com.my/ https://*.google.co.mz/ https://*.google.com.na/ https://*.google.com.ng/ https://*.google.com.ni/ https://*.google.ne/ https://*.google.nl/ https://*.google.no/ https://*.google.com.np/ https://*.google.nr/ https://*.google.nu/ https://*.google.co.nz/ https://*.google.com.om/ https://*.google.com.pa/ https://*.google.com.pe/ https://*.google.com.pg/ https://*.google.com.ph/ https://*.google.com.pk/ https://*.google.pl/ https://*.google.pn/ https://*.google.com.pr/ https://*.google.ps/ https://*.google.pt/ https://*.google.com.py/ https://*.google.com.qa/ https://*.google.ro/ https://*.google.ru/ https://*.google.rw/ https://*.google.com.sa/ https://*.google.com.sb/ https://*.google.sc/ https://*.google.se/ https://*.google.com.sg/ https://*.google.sh/ https://*.google.si/ https://*.google.sk/ https://*.google.com.sl/ https://*.google.sn/ https://*.google.so/ https://*.google.sm/ https://*.google.sr/ https://*.google.st/ https://*.google.com.sv/ https://*.google.td/ https://*.google.tg/ https://*.google.co.th/ https://*.google.com.tj/ https://*.google.tl/ https://*.google.tm/ https://*.google.tn/ https://*.google.to/ https://*.google.com.tr/ https://*.google.tt/ https://*.google.com.tw/ https://*.google.co.tz/ https://*.google.com.ua/ https://*.google.co.ug/ https://*.google.co.uk/ https://*.google.com.uy/ https://*.google.co.uz/ https://*.google.com.vc/ https://*.google.co.ve/ https://*.google.vg/ https://*.google.co.vi/ https://*.google.com.vn/ https://*.google.vu/ https://*.google.ws/ https://*.google.rs/ https://*.google.co.za/ https://*.google.co.zm/ https://*.google.co.zw/ https://*.google.cat/; style-src 'self' https://*.sentry-cdn.com https://*.ingest.sentry.io https://*.sampleassets.com https://*.stripe.com https://cdn.rawgit.com https://cdn.jsdelivr.net https://www.google.com https://www.google-analytics.com https://www.gstatic.com https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/ https://www.googletagmanager.com https://*.doubleclick.net https://project.dev https://*.project.dev https://project.dev https://fonts.googleapis.com https://fonts.gstatic.com 'unsafe-inline'; font-src 'self' https://project.dev https://*.project.dev https://project.dev https://fonts.googleapis.com https://fonts.gstatic.com data: ; frame-src 'self' https://*.sentry-cdn.com https://*.ingest.sentry.io https://*.sampleassets.com https://*.stripe.com https://cdn.rawgit.com https://cdn.jsdelivr.net https://www.google.com https://www.google-analytics.com https://www.gstatic.com https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/ https://www.googletagmanager.com https://*.doubleclick.net https://project.dev https://*.project.dev https://project.dev; object-src 'none'; media-src 'unsafe-inline' data: 'self' https://*.sentry-cdn.com https://*.ingest.sentry.io https://*.sampleassets.com https://*.stripe.com https://cdn.rawgit.com https://cdn.jsdelivr.net https://www.google.com https://www.google-analytics.com https://www.gstatic.com https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/ https://www.googletagmanager.com https://*.doubleclick.net https://project.dev https://*.project.dev https://project.dev; child-src 'self' blob: ; manifest-src 'self'; connect-src 'self' https://*.sentry-cdn.com https://*.ingest.sentry.io https://*.sampleassets.com https://*.stripe.com https://cdn.rawgit.com https://cdn.jsdelivr.net https://www.google.com https://www.google-analytics.com https://www.gstatic.com https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/ https://www.googletagmanager.com https://*.doubleclick.net https://project.dev https://*.project.dev https://project.dev; base-uri 'self'; upgrade-insecure-requests;
Now lets assume that this policy works well, but somehow I would like to have violations reported (to adapt the policy in case it is required).
Tried to set a header like this:
Content Security Policy: report-uri https://meow.ingest.sentry.io/api/meow/security/?sentry_key=meow;
However, it looks like violations of the CSP are not reported although this header is set. It works perfectly if I set the policy in the header though. Is there a solution to make reporting work with the meta tag?
Edit: Have tried the new report-to
header, with setting report-to
within the policy. That also does not work :/
I have found a solution:
<meta http-equiv="Content-Security-Policy" content="[CSP_CONTENT_HERE]">
<script nonce="[CSP_NONCE_HERE]">
document.addEventListener('securitypolicyviolation', function (event) {
console.log(event)
let config = JSON.parse('{"keys" : ["blockedURI", "columnNumber", "disposition", "documentURI", "effectiveDirective", "lineNumber", "originalPolicy", "referrer", "sample", "sourceFile", "statusCode", "violatedDirective"],"reportUri" : "[YOUR_REPORT_URI_HERE]"}');
let reportKeys = {'blockedURI':'blocked-uri', 'columnNumber':'column-number', 'documentURI':'document-uri', 'effectiveDirective':'effective-directive', 'lineNumber':'line-number', 'originalPolicy':'original-policy', 'sourceFile':'source-file', 'statusCode':'status-code', 'violatedDirective':'violated-directive'};
let json = {'csp-report': {}};
for (let i = 0, len = config.keys.length; i < len; i++) {
if (event[config.keys[i]] !== 0 && event[config.keys[i]] !== '') {
json['csp-report'][(reportKeys[config.keys[i]] ? reportKeys[config.keys[i]] : config.keys[i])] = event[config.keys[i]];
}
}
let xhr = new XMLHttpRequest();
xhr.open('POST', config.reportUri, true);
xhr.setRequestHeader('content-type', 'application/csp-report');
xhr.send(JSON.stringify(json));
});
</script>
So instead of setting some kind of report uri or configuring report to, you have a JS event listener securitypolicyviolation
. From the event you can get all parameters which might be interesting for the report, you send them to your desired report URI.
Script is taken from here, I did not like the idea to add another external script though: https://report-uri.github.io/report-uri-js-demo/
Just have a look at the placeholders: