TL;DR - CSP nonces aren't as effective as they seem to be against DOM XSS. You can bypass them in several ways. We don't know how to fix them. Maybe we shouldn't.
Thank you for visiting. This blog post talks about CSP nonce bypasses. It starts with some context, continues with how to bypass CSP nonces in several situations and concludes with some commentary. As always, this blog post is my personal opinion on the subject, and I would love to hear yours .
My relationship with CSP, " it's complicated "
I used to like Content-Security-Policy. Circa 2009, I used to be really excited about it. My excitement was high enough that I even spent a bunch of time implementing CSP in javascript in my ACS project (and to my knowledge this was the first working CSP implementation/prototype). It supported hashes, and whitelists, and I was honestly convinced it was going to be awesome! My abstract started with "How to solve XSS [...]" .But one day one of my friends from elhacker.net ( WHK ) pointed out that ACS (and CSP by extension) could be trivially circumvented using JSONP. He pointed out that if you whitelist a hostname that contains a JSONP endpoint, you are busted, and indeed there were so many, that I didn't see an easy way to fix this. My heart was broken.:broken_heart:
Fast-forward to 2015, when Mario Heiderich made a cool XSS challenge called "Sh*t, it's CSP!" , where the challenge was to escape an apparently safe CSP with the shortest payload possible. Unsurprisingly, JSONP made an appearance (but also Angular and Flash). Talk about beating a dead horse.
And then finally in 2016 a reasonably popular paper called " CSP Is Dead, Long Live CSP! " came out summarizing the problems highlighted by WHK and Mario after doing an internet-wide survey of CSP deployments, performed by Miki , Lukas , Sebastian and Artur . The conclusion of the paper was that CSP whitelists were completely broken and useless. At least CSP got a funeral , I thought.
However, that was not it. The paper, in return, advocated for the use of CSP nonces instead of whitelists. A bright future for the new way to do CSP!
When CSP nonces where first proposed, my concern with them was that their propagation seemed really difficult. To solve this problem, dominatrixss-csp back in 2012 made it so that all dynamically generated script nodes would work by propagating the script nonces with it's dynamic resource filter . This made nonce propagation really simple. And so, this exact approach was proposed in the paper, and named strict-dynamic , now with user-agent support, rather than a runtime script as dominatrixss-csp was. Great improvement. We got ourselves a native dominatrixss!
This new flavor of CSP , proposed to ignore whitelists completely, and rely solely on nonces. While the deployment of CSP nonces is harder than whitelists (as it requires server-side changes on every single page with the policy), it nevertheless seemed to propose real security benefits, which were clearly lacking on the whitelist-based approach. So yet again, this autumn, I was reasonably optimistic of this new approach. Perhaps there was a way to make most XSS actually *really* unexploitable this time. Maybe CSP wasn't a sham after all!
But this Christmas, as-if it was a piece of coal from Santa, Sebastian Lekies pointed out what in my opinion, seems to be a significant blow to CSP nonces, almost completely making CSP ineffective against many of the XSS vulnerabilities of 2016.
A CSS+CSP+DOM XSS three-way
While CSP nonces indeed seem resilient against 15-years-old XSS vulnerabilities, they don't seem to be so effective against DOM XSS. To explain why, I need to show you how web applications are written now a days, and how that differs from 2002.
Before, most of the application logic lived in the server, but in the past decade it has been moving more and more to the client. Now a days, the most effective way to develop a web application is by writing most of the UI code in HTML+JavaScript. This allows, among other things for making web applications offline-ready, and provides access to an endless supply of powerful web APIs.
And now, newly developed applications still have XSS, the difference is that since a lot of code is written in JavaScript, now they have DOM XSS. And these are precisely the types of bugs that CSP nonces can't consistently defend against (as currently implemented, at least).
Let me give you three examples (non-exhaustive list, of course) of DOM XSS bugs that are common and CSP nonces alone can't defend against:
Persistent DOM XSS when the attacker can force navigation to the vulnerable page, and the payload is not included in the cached response (so need to be fetched). DOM XSS bugs where pages include third-party HTML code (eg, fetch(location.pathName).then(r=>r.text()).then(t=>body.innerHTML=t);) DOM XSS bugs where the XSS payload is in the location.hash (eg, https://victim/xss#!foo?payload= ). To explain why, we need to travel back in time to 2008 (woooosh!). Back in 2008, Gareth Heyes , David Lindsay and I made a small presentation in Microsoft Bluehat called CSS - The Sexy Assassin . Among other things, we demonstrated a technique to read HTML attributes purely with CSS3 selectors (which was coincidentallyrediscovered by WiSec and presented with kuza55 on their 25c3 talk