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-yFhOXjjJO1K/wXXK71DCwu/9' '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-yFhOXjjJO1K/wXXK71DCwu/9'
meansscript
&style
elements withnonce="yFhOXjjJO1K/wXXK71DCwu/9"
attribute-
'report-sample'
instructs the browser to include a violation sample, the first 40 characters (valid for CSS, JS only but included indefault-src
here to keep the header short)
report-to
: name of the group where to send violation reports to
The Report-To
response header:
Report-To: {"group":"default","max_age":1800,"endpoints":[{"url":"https://edge.has.report/report"}],"include_subdomains":true}
group
: the name of the group, the same as in the CSP header in thereport-to
directivemax_age
: how long the browser should use the endpoint and report errors to it-
endpoints
: reporting endpoint configuration, can specify multiple endpoints but reports will be sent to just one of themurl
: where to send reports to, must behttps://
, otherwise the endpoint will be ignored
Try it with images
an image from https://www.michalspacek.cz (allowed)
<script nonce="yFhOXjjJO1K/wXXK71DCwu/9">
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, possibly grouped with other reports (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="yFhOXjjJO1K/wXXK71DCwu/9">
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 nononce
attribute - Will trigger a report that will be sent asynchronously, possibly grouped with other reports (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)
-
Notable changes in the Editor's Draft are switching to structured headers (
Reporting-Endpoints
instead ofReport-To
) and moving out concrete reports into the following separate Draft Community Group Reports: Crash Reporting, Deprecation Reporting, Intervention Reporting