240

W3C says there is a new attribute in HTML5.1 called nonce for style and script that can be used by the Content Security Policy of a website.

I googled about it but finally didn't get it what actually this attribute does and what changes when using it?

ata
  • 3,398
  • 5
  • 20
  • 31
  • 5
    Looks like it's just an extra bit of security for your site, you add it to a link or a form and when the page is served, if the nonce doesn't match yours, then you don't serve the page – Pete Mar 21 '17 at 09:44
  • @Pete You mean then nobody could load your `script` and `style`? Something like hotlink ban? – ata Mar 21 '17 at 09:50
  • it's also for normal pages and form validation – Pete Mar 21 '17 at 09:56

1 Answers1

328

The nonce attribute lets you “whitelist” certain inline script and style elements, while avoiding use of the CSP unsafe-inline directive (which would allow all inline script and style), so you still retain the key CSP feature of disallowing inline script/style in general.

So the nonce attribute is a way to tell browsers the inline contents of a particular script or style element weren’t injected into the document by some (malicious) third party, but were instead put in the document intentionally by whoever controls the server the document is served from.


The Web Fundamentals Content Security Policy article’s If you absolutely must use it section has a good example of how to use the nonce attribute, which amounts to the following steps:

  1. For each request your web server gets for a particular document, have your backend make a random base64-encoded string of at least 128 bits from a cryptographically secure random number generator; e.g., EDNnf03nceIOfn39fn3e9h3sdfa. That’s your nonce.

  2. Take the nonce generated in step 1, and for any inline script/style you want to “whitelist”, make your backend code insert a nonce attribute into the document before it’s sent over the wire, with that nonce as the value:

     <script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">…</script>
    
  3. Take the nonce generated in step 1, prepend nonce-, and make your backend generate a CSP header with that among the values of the source list for script-src or style-src:

     Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
    

So the mechanism of using a nonce is an alternative to instead of having your backend generate a hash of the contents of the inline script or style you want to allow, and then specifying that hash in the appropriate source list in your CSP header.


Note: browsers don’t (can’t) check that the nonce values which servers send actually change between page requests; and so, it’s possible — though totally inadvisable — to skip 1 above and not have your backend do anything dynamically for the nonce, in which case you could just put a nonce attribute with a static value into the HTML source of your doc, and send a static CSP header with that same nonce value.

But the reason you’d not want to use a static nonce in that way is, it’d pretty much defeat the entire purpose of using the nonce at all to begin with — because, if you were to use a static nonce like that, at that point you might as well just be using unsafe-inline.


As far as which elements are “nonceable”: The CSP spec currently restricts browsers to checking nonces only for script and style elements. Here are the spec details:

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
  • Then `nonce` use for verifying user? What verification is required for `style`? – ata Mar 21 '17 at 10:25
  • 33
    It’s not for verifying the user—it’s for verifying that the inline contents of a particular script or style element were not injected into the document my some (malicious) third party, but were instead put into the document intentionally by whoever controls the server the document is served from. (I’ll update my answer to say that.) – sideshowbarker Mar 21 '17 at 10:29
  • One thing else, let say one site has considerable traffic so thousands of `nonce`s are created and stored. It definitely reduces the server performance. If this site has no important data receiving from user, like passwords or bank account, is there any reason for putting this effort and using this attribute? – ata Mar 21 '17 at 11:06
  • 5
    The nonces don’t need to be stored—instead they’re generated in memory and inserted into CSP header and the HTML document that’s sent over the wire in responses (not to the source stored on the server filesystem/database). – sideshowbarker Mar 21 '17 at 11:26
  • 5
    As far as any reason for putting effort into using the `nonce` attribute, if you don’t absolutely need to use it, then don’t. It’s really only meant for cases where for some reason you can’t (yet) get rid of some inline script or style contents from a particular document (but should be removing it later). So if some reason you’re stuck with needing to keep inline script and style contents, then in the mean time you can at least use the nonce mechanism to let browsers verify they’re OK. Otherwise you should just fully use CSP as actually intended, & not allow any inline script or style elements – sideshowbarker Mar 21 '17 at 11:32
  • 5
    @sideshowbarker, What does an empty nonce do? I'm seeing pages with ` – Pacerier Oct 18 '17 at 15:23
  • 2
    @Pacerier In those cases, what `nonce-*` values (if any) do you see in the Content-Security-Policy response header or `` element for those pages? Regardless, an empty `nonce` attribute has no effect except to always fail any CSP nonce check, because any `nonce-*` value in a CSP policy must be non-empty per the requirements in the CSP spec. See https://w3c.github.io/webappsec-csp/#match-nonce-to-source-list. So I’d guess those empty `nonce` attributes you’re seeing are just cases where the backend failed to populate the value before serving the page. – sideshowbarker Oct 18 '17 at 16:51
  • 13
    Note: If your script is static, I recommend a CSP hash, rather than a nonce. – Brian Mar 07 '18 at 17:40
  • 6
    If someone "in the middle" manages to inject an inline script in your page, how difficult is it for them to put a nonce in it and also alter CSP headers? – Nicolas Hoizey Jul 27 '18 at 07:50
  • 3
    @NicolasHoizey There is no general answer to your question, but it may be much more difficult. Injecting inline script into your page is possible via stored/reflected XSS attack (fairly common vulnerability). But you usually can not alter headers sent by server from JS. To do that, you would have to get remote code execution on the target server - and well, when that's the case, things are already pretty bad nothing will save you. – FanaticD Aug 09 '18 at 06:51
  • 1
    Another question to bounce off that last one. Could a hacker view the nonce in the CSP header from the server and inject a script with a nonce that matches the server? – dmikester1 Mar 14 '19 at 19:55
  • 1
    @dmikester1 if a hacker has access to the server, they can do whatever they want with the web page. – Aaronius May 13 '19 at 15:02
  • 1
    @dmikester1 If the attacker can view the header prior to injection (regardless of whether they have server access), you're boned with respect to the nonce. – DylanYoung Sep 30 '19 at 17:01
  • @sideshowbarker. Chrome can generate 'flash css', where the pre-css loaded page is shown momentarily before the css is applied. It is a PITA! I had to use an inline `style` tag in the `head` tag with very basic `body` styles, with its content `{display:none}`, until the end of the css file loads, wherein the content inside the `body` tag is unhidden. Of course, if one has static 'above the line' content, it could be set to be displayed initially, with all the appropriate styles inline, and just enable the rest of the content when the css file is loaded. – Patanjali Feb 28 '20 at 20:59
  • @sideshowbarker. The inline `body` styles also prevent Chrome generating a white flash between pages that are dark. Actually, I think that both Chrome issues are related, in that they might be because of delays in loading css. My css is dynamic, and is processed by PHP first, which might be delaying it too much, even if only slightly. I don't know if those whose pages generate the interpage white flash have a large css file or other loading delay. The background of the raw non-css pages are white. – Patanjali Feb 28 '20 at 21:09
  • i came to this answer from this page (https://webpack.js.org/guides/csp) - i added this to entry file in webpack: `__webpack_nonce__ = 'something-tricky';`, and then used `Content-Security-Policy: script-src 'nonce-something-tricky'` and get `Refused to load the script 'http://localhost:3000/js/bundle.js' because it violates the following Content Security Policy directive: "script-src 'nonce-something-tricky'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.` – user1063287 Aug 29 '20 at 15:15
  • 1
    Link is now https://developers.google.com/web/fundamentals/security/csp/#if_you_absolutely_must_use_it_ – marcellothearcane Sep 21 '20 at 09:56
  • 1
    Thanks Martin — I’ve fixed the URL (and thanks @marcellothearcane too) – sideshowbarker Oct 05 '20 at 22:20
  • 2
    @user1073287 and everyone else - do **NOT** use static nonce values! This ruins the purpose of a nonce. They should be generated differently _each time the page loads_ otherwise hackers can crack them easily. It is much better to use hashes. – marcellothearcane Oct 06 '20 at 05:01
  • Nice clear answer. In my opinion the current structure of HTML as essentially insecure, requiring all sorts of kludgy fixup mechanisms, is a big mistake by the standards groups. They should create an incompatible secure Web, with a simple strategy for gradually changing over to it. The same comment applies to standard email. Note the relative freedom in using PHP, which is naturally secure (when the rest of a site is secure). Let's make HTML web pages naturally secure, too! – David Spector Feb 10 '21 at 16:19