report-to
Sending Content Security Policy (CSP) violation reports with Reporting API using the Report-To
header, asynchronously and out-of-band, when the browser feels like, possibly grouped with other reports and even other report types.
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-jKKbuVy+yIVZ+J5xY9hPoi3R' 'self' 'report-sample'; style-src 'self' 'nonce-jKKbuVy+yIVZ+J5xY9hPoi3R'; 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-jKKbuVy+yIVZ+J5xY9hPoi3R'
means script
elements with nonce="jKKbuVy+yIVZ+J5xY9hPoi3R"
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 group where to send violation reports toReport-To
response header:Report-To: {"group":"default","max_age":1800,"endpoints":[{"url":"https://nasal.has.report/report"}],"include_subdomains":true}
group
: the name of the group, the same as in the CSP header in the report-to
directivemax_age
: how long the browser should use the endpoint and report errors to itendpoints
: reporting endpoint configuration, can specify multiple endpoints but reports will be sent to just one of them
url
: where to send reports to, must be https://
, otherwise the endpoint will be ignoredanother image from https://www.michalspacek.cz (allowed)
<script nonce="jKKbuVy+yIVZ+J5xY9hPoi3R">
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="jKKbuVy+yIVZ+J5xY9hPoi3R">
document.getElementById('blocked').onclick = function(e) {
document.getElementById('image').src = 'https://example.com/image.png';
}
</script>
(allowed, the script
tag contains nonce="jKKbuVy+yIVZ+J5xY9hPoi3R"
)
<script nonce="jKKbuVy+yIVZ+J5xY9hPoi3R">
document.getElementById('js').onclick = function(e) {
alert('hi');
};
</script>
Simulate an attacker:
blocked JS tag
<script nonce="jKKbuVy+yIVZ+J5xY9hPoi3R">
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">
Reporting-Endpoints
instead of Report-To
) and moving out concrete reports into the following separate Draft Community Group Reports:
Crash Reporting,
Deprecation Reporting,
Intervention Reporting