tl;dr: you can keep caching responses with nonces in them like you normally would, and CSP will still provide a strong defense against common XSS attacks.
This is an interesting question: when a page containing CSP nonces gets cached (in a public/back-end cache) that would result in the same nonce being transmitted to multiple users. This sounds bad, because nonces are not supposed to be reused. However, quite often this is not a problem in practice.
Let's say you as an attacker are served the same nonce as your victim on a response to the URL /foo/bar
. Now you could use this nonce in your XSS payload. Let's consider two of the most common XSS scenario's:
- URL parameter based reflected XSS:
/foo/bar?payload=...
will likely have a different cache key than /foo/bar
, therefore causing the user to be delivered a fresh response with a new nonce. The attack fails.
- Stored XSS in dynamic HTML: your payload is now included when the user loads
/foo/bar
. However, if the user refreshes and gets a response from the cache, then this won't include your injected XSS payload. Alternatively, if they get a fresh response they will also get a fresh nonce. In either case the attack fails.
Now, this doesn't mean that this situation can never be exploited: for example, if /foo/bar
has vulnerable JavaScript that modifies the DOM in a way that the attacker payload can be injected it might possible to use the cached nonce. Think of DOM based XSS attacks via data in the #
segment of a URL or in AJAX responses.
It will be much trickier for an attacker to exploit the latter situation though, which may be sufficient since the point of CSP is to just provide defense-in-depth; it can not guarantee immunity for 100% of XSS attacks.
If you still want to defend against this scenario: you can disable public caching for HTML responses. Private/browser caching is still fine, however, and you can also safely keep caching any non-HTML resources.