4

I am in the process of adding CSP headers to a site that has a long way to go before it can adopt a strict policy. There are quite a few inline scripts, so I am using nonce- to allow specific inline scripts. I have found that it doesn't work on the onload attribute of a script tag with src. Here's an example:

// header:
Content-Security-Policy: script-src self https: 'nonce-d3adbe3fed'

<script async defer src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js" nonce="d3adbe3fed" onload="console.log('onload', _.VERSION)"></script>

Full working demo at https://brave-pasteur-0d438b.netlify.com/

Chrome gives the following error:

Refused to execute inline event handler because it violates the following Content Security Policy directive: "script-src self https: 'nonce-d3adbe3fed'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.

The message suggests that it should be possible to enable inline event handlers with a nonce, but as far I as I can tell, nonce is only intended to work on inline scripts.

This is just a demo, but the use case is an async/deferred tracking script which loads the tracking library, then in the onload handler makes a tracking call to the loaded library.

Is it possible to use a nonce on an onload or other event handler attribute, or will I need to change my implementation? Using script-src 'unsafe-inline' or script-src-attr 'unsafe-inline' is not an option, as those are the vulnerabilities I am specifically trying to address. And putting the contents of the onload handler into a separate script following the script tag is also not an option because the script is async deferred, and needs to stay that way.

undefined
  • 6,208
  • 3
  • 49
  • 59
  • 1
    The error message is misleading. See https://github.com/w3c/webappsec/issues/468 and see the comment at https://stackoverflow.com/questions/50842033/csp-hash-or-nonce-for-inline-js-within-attribute#comment88688963_50842033. Despite what that error message would seem to imply, in CSP2 and in current browsers, only element contents are “nonceable” — and event-handler attributes aren’t. – sideshowbarker Jun 01 '19 at 04:08
  • But see also the answer at https://stackoverflow.com/a/44609372/441757. CSP3 adds a new `unsafe-hashes` expression for allowing particular inline scripts/styles. See https://w3c.github.io/webappsec-csp/#unsafe-hashes-usage. And for more details see the *Explainer: ‘unsafe-hashes’, ‘unsafe-inline-attributes’ and CSP directive versioning* document at https://docs.google.com/document/d/1_nYS4gWYO2Oh8rYDyPglXIKNsgCRVhmjHqWlTAHst7c/edit#heading=h.ue3d7ohicxh3. But the `unsafe-hashes` feature hasn’t shipped in any browsers other than Chrome: https://www.chromestatus.com/feature/5867082285580288 – sideshowbarker Jun 01 '19 at 04:16
  • 1
    Note too: the language in the CSP2 spec makes a bit more clear what nonces can & can’t be used with; it has a specific section explicitly titled **Nonce usage for script elements** https://w3.org/TR/CSP2/#script-src-nonce-usage but no similar section titled “Nonce usage for event handlers” (or such). (In general, when trying to figure out CSP requirements and behavior, I often find the language in the (old) https://w3.org/TR/CSP2 spec states them in a much more developer-friendly (versus browser-implementor-friendly) way than the current spec at https://w3c.github.io/webappsec-csp does) – sideshowbarker Jun 01 '19 at 10:32
  • 1
    One more note for future readers: hash values don't work on event handlers either. So the only way to allow a specific inline event handler is to allow all event handlers. In my opinion, this is a major failure of current CSP implementations. – undefined Jun 03 '19 at 22:59
  • Making hash values work on event handlers is what the new CSP3 `unsafe-hashes` expression is for. Though as I mentioned in a previous comment, `unsafe-hashes` support hasn’t shipped in any browsers other than Chrome https://www.chromestatus.com/feature/5867082285580288, the failure in this case at least isn’t due to the spec authors neglecting to define a mechanism for it — it’s instead that the other browser projects have failed to prioritize implementing it. Maybe part of the reason for that is, they just haven’t heard from enough developers who believe they should prioritize it higher. – sideshowbarker Jun 04 '19 at 02:14

2 Answers2

3

If there is a way to use nonce on an inline handler, I will accept an answer that demonstrates it. Unfortunately, at the time of writing, I don't think there is.

As a workaround, the following script exhibits the same behavior and timing as an script with async/defer and an onload handler, while satisfying the specified CSP policy:

<script nonce="d3adbe3fed">
    let s = document.createElement('script');
    s.src = 'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js';
    s.onload = () => console.log(_.VERSION);
    document.documentElement.appendChild(s);
</script>

Of course, the long term solution is to eliminate inline scripts completely, but in the short term that isn't always feasible, and it is better to implement a more lax policy quickly, than to put it off and have no CSP at all.

undefined
  • 6,208
  • 3
  • 49
  • 59
0

As previously noted nonces won't work (at least at the moment - January of 2023) for inline JS event handlers - but you can use the less safe unsafe-hashes option if you can't or don't want to change your inline script. The procedure is below.

Generate your hash using this command:

echo -n "console.log('onload', _.VERSION)" | openssl dgst -sha256 -binary | openssl base64

and then use it like:

Content-Security-Policy: script-src 'unsafe-hashes' 'sha256-YOUR_HASH_HERE';

in this case the hash YOUR_HASH_HERE would be: is6kBKp90zgPWiqfkihufUS6bhRViGwlIg8RlEV7MgA=

Picard
  • 3,745
  • 3
  • 41
  • 50
  • how can you completely remove window.onload event?. Meaning, that is what i have and it gets blocked by CSP with strict mode and nonce, but i see no other way of performing it (CSP compliant way that is). – Kosem Mar 05 '23 at 11:41
  • But where is your event defined? Inline or within some included script? – Picard Mar 07 '23 at 10:54