Search code examples
http-headersreportingcontent-security-policymeta-tagssentry

Content Security Policy (CSP): Is it somehow possible to report violations if using meta tag?


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 :/


Solution

  • 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:

    • [CSP_CONTENT_HERE]: Your CSP definition
    • [YOUR_REPORT_URI_HERE]: Your report URI (e.g. Sentry)
    • [CSP_NONCE_HERE]: Your CSP nonce, in case you use CSP nonces.