Content Security Policy Report-Only with report-to
Loading images, executing JavaScript and everything else as usual but sending a Content Security Policy (CSP) violation report (with "disposition": "report" instead of "disposition": "enforce") if something would go wrong.
CSP is a policy that lets the authors (or server administrators) of a web application inform the browser about the sources from which the application expects to load resources like images, scripts, styles, or even where to submit forms.
This Report-Only mode works with both report-uri and report-to directives, and is usually used for policy upgrades – an app can send both Content-Security-Policy and Content-Security-Policy-Report-Only headers with different policies.
The CSPRO (CSP Report-Only) response header:
Content-Security-Policy-Report-Only: default-src data: 'self' 'nonce-2CN0N77R5qUI+T6bRketdW6E' 'report-sample'; report-to default
-
default-src: what's allowed by default, includes images, fonts, JavaScript and moredata:used for the placeholder image below'self'means current URL's origin (scheme + host + port)'nonce-2CN0N77R5qUI+T6bRketdW6E'meansscript&styleelements withnonce="2CN0N77R5qUI+T6bRketdW6E"attribute-
'report-sample'instructs the browser to include a violation sample, the first 40 characters (valid for CSS, JS only but included indefault-srchere to keep the header short)
report-to: name of the endpoint where to send violation reports, as defined in theReporting-Endpointsheader
The Reporting-Endpoints response header:
Reporting-Endpoints: default="https://slum.has.report/report"
default: the name of the endpoint, the same as in the CSP header in thereport-todirective"url": where to send reports, must behttps://, otherwise the endpoint will be ignored-
You may provide multiple
name="url"endpoints separated by comma (,)- For example:
Reporting-Endpoints: csp-reporting="https://example.com/csp", nel-reporting="https://example.com/nel"
- For example:
Try it with images
an image from https://www.michalspacek.cz (allowed)
<script nonce="2CN0N77R5qUI+T6bRketdW6E">
document.getElementById('allowed').onclick = function(e) {
document.getElementById('image').src = 'https://www.michalspacek.cz/i/images/photos/michalspacek-trademark-400x268.jpg';
}
</script>
- Allowed even though the image was loaded from https://www.michalspacek.cz and not from this origin
- Will trigger a report that will be sent asynchronously (violation visible in Developer Tools in the Console tab, you won't see the report in Network tab but you can still view the reporting requests)
- Check your reports (can take some time before the browser sends the report)
… and with JavaScript
<script nonce="2CN0N77R5qUI+T6bRketdW6E">
document.getElementById('insert').onclick = function() {
const script = document.createElement('script');
script.text = 'document.getElementById("here").innerHTML = "by JavaScript with <code>document.getElementById('here').innerHTML</code>";';
document.getElementById('insert').insertAdjacentElement('afterend', script);
alert('Text inserted');
}
</script>
-
Allowed even though it's inserted by an inline JavaScript (the code between
<script>and</script>) and not loaded from this origin ('self'doesn't include inline JavaScript), and has nononceattribute - Will trigger a report that will be sent asynchronously (violation visible in Developer Tools in the Console tab, you won't see the report in Network tab but you can still view the reporting requests)
- Check your reports (can take some time before the browser sends the report)
- See the inserted JS tag in Developer tools, right after
<button id="insert">
Related specs & documents
- Content Security Policy Level 3 Working Draft
- Content Security Policy Level 2
- Content Security Policy 1.0 (discontinued)
- Reporting API Working Draft
- Reporting API Editor's Draft (which will evolve into a Working Draft, followed by a Recommendation eventually)