Up until now we've had to rely on GET parameters to identify whether CSP reports were enforced or sent as part of a report-only policy. This added friction for the host and on report-uri.io I've seen a lot of problems caused by this. Things are set to change.


Sending reports

When a browser sends a CSP report it includes various values within it. Here's what one typically looks like:


{
    "csp-report": {
        "blocked-uri": "https://evil.com",
        "document-uri": "https://securityheaders.io/",
        "original-policy": "{policy goes here}",
        "violated-directive": "script-src ..."
    }
}

It provides all of the information you need, and often various other bits too, but it doesn't say anywhere whether it actually blocked something or if this was from a report-only policy. We're left to do that ourselves via the reporting address, which is why I have two different options on report-uri.io to choose from.


CSP reporting addresses


This means it's down to you as the host to indicate whether the header was enforced or report-only and to remember to change that when you change the policy, and you'd be amazed at how many people forget to do that! Yes, I know it's easy to do and easy to fix if you do forget but I just kind of sit here thinking "why?". It really seems like this is something that should be handled automatically and I raised a bug in the W3C Web Application Security Working Group to address this. Unfortunately it didn't go very far and was later moved to the CSP specific bug tracker. It was then raised again a little later and we got an update.


Indicating disposition

The reason that I started digging into this again was that I started getting alerts from report-uri.io about inbound reports that contained unexpected fields. I get these now and again when a browser or proxy does crazy things, sometimes people send manually crafted reports with odd fields or whatever it is that happens but I largely ignore them and just look for the fields I want in the report. I started to take note when the frequency of these was a lot higher than I'd first realised and it turns out there was a new "policy-disposition" field that had a value of either "enforce" or "report". This has now been added to the more general SecurityPolicyViolationEvent so will also apply to a lot more than just CSP reports, think HPKP et al. If you're interested here is the change in Chromium and the intent to ship.


{
    "csp-report": {
        "blocked-uri": "https://evil.com",
        "document-uri": "https://securityheaders.io/",
        "original-policy": "{policy goes here}",
        "violated-directive": "script-src ...",
        "disposition": "enforce"
    }
}

Using the field

Because the field is new, literally brand new, I can't depend on it exclusively just yet but it will still be useful and will become more so over time. The change hit Chrome v56 a few weeks ago and huge numbers of clients are sending it already. What I'm going to do for now is add support to report-uri.io to detect the value if it is present and override the value set in the reporting address if appropriate. If the user has set the reportOnly flag on their address but the browser is indicating enforce, I will go with that. This will help remove issues where the address hasn't been updated and eventually I hope I can get rid of the need to indicate this at all. We just have to wait for browser support for that...