report-toSending Content Security Policy (CSP) violation reports with Reporting API using the Reporting-Endpoints header, asynchronously and out-of-band, when the browser feels like.
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.
Content Security Policy is not intended as a first line of defense against content injection vulnerabilities like Cross-Site Scripting (XSS). Instead, CSP is best used as defense-in-depth, to reduce the harm caused by content injection attacks.
The report-to directive using the Reporting API replaces the deprecated report-uri directive in Content Security Policy level 3 spec, which is not yet fully supported by all major clients.
To support more browsers, apps usually send both report-uri and report-to in their CSP headers.
Content-Security-Policy: default-src 'none'; img-src 'self' https://www.michalspacek.cz; script-src 'nonce-uYkDK76OEPJVkXgxG9X157jG' 'self' 'report-sample'; style-src 'self' 'nonce-uYkDK76OEPJVkXgxG9X157jG'; report-to default
default-src: what's allowed by default, includes images, fonts, JavaScript and moreimg-src: where to load images from, overrides default-src for images
'self' means current URL's origin (scheme + host + port)script-src: what JavaScript is allowed to be executed
'nonce-uYkDK76OEPJVkXgxG9X157jG' means script elements with nonce="uYkDK76OEPJVkXgxG9X157jG" attribute'report-sample' instructs the browser to include the first 40 characters of the blocked JavaScript in the reportstyle-src: allowed CSS sourcesreport-to: name of the endpoint where to send violation reports, as defined in the Reporting-Endpoints headerReporting-Endpoints response header:Reporting-Endpoints: default="https://cancer.has.report/report"
default: the name of the endpoint, the same as in the CSP header in the report-to directive"url": where to send reports, must be https://, otherwise the endpoint will be ignoredname="url" endpoints separated by comma (,)
Reporting-Endpoints: csp-reporting="https://example.com/csp", nel-reporting="https://example.com/nel"
another image from https://www.michalspacek.cz (allowed)
<script nonce="uYkDK76OEPJVkXgxG9X157jG">
document.getElementById('allowed').onclick = function(e) {
document.getElementById('image').src = 'https://www.michalspacek.cz/i/images/photos/michalspacek-webtop100-400x268.jpg';
}
</script>
Now simulate an attacker:
an image from https://example.com
<script nonce="uYkDK76OEPJVkXgxG9X157jG">
document.getElementById('blocked').onclick = function(e) {
document.getElementById('image').src = 'https://example.com/image.png';
}
</script>
(allowed, the script tag contains nonce="uYkDK76OEPJVkXgxG9X157jG")
<script nonce="uYkDK76OEPJVkXgxG9X157jG">
document.getElementById('js').onclick = function(e) {
alert('hi');
};
</script>
Simulate an attacker:
blocked JS tag
<script nonce="uYkDK76OEPJVkXgxG9X157jG">
document.getElementById('inject').onclick = function() {
const script = document.createElement('script');
script.text = 'console.log("lo")';
document.getElementById('inject').insertAdjacentElement('afterend', script);
}
</script>
document.createElement() doesn't have a nonce<button id="inject">