Last updated at Tue, 26 Dec 2023 21:32:30 GMT
This week, tCell sponsored BSidesSF. Many things I’ve heard about the conference proved to be true, and the technical depth of conversations I had at our table was definitely enough to keep me on my toes. One of the most interesting conversations was with a company that wanted to talk about Content Security Policies (CSP). They had come to the conclusion that new revisions of the PCI security standards would require that they implement CSP and work much harder to control inline scripts on their application suite.
CSP Nonces, Scripts and Controlling Script Execution, oh my!
CSPs are an important component of defending against XSS attacks because they prevent a user’s browser from loading content from someplace they shouldn’t. (I’ve previously written about using CSP as a method of defending against unauthorized insertion of Coinhive into a web page you control.)
CSP is near and dear to our hearts here at tCell (as you can read about here). Today’s web applications have pushed a great deal of functionality into the browser, and that code is increasingly responsible for app logic. One of the principles of the tCell architecture is that any place there’s executable code, security controls need to be present. One of the ways that we protect the complete application as it executes on both the user’s browser and on the server is through the browser agent, a lightweight JavaScript that monitors the DOM as it is built, as well as watching for inline scripts. The browser agent gives you excellent visibility into how the application runs because of the reporting powered by our cloud analytics: what scripts were run, where did the load from, and is this what you expected to see?
The discussion I had with these security engineers centered around CSP nonces, specifically, on how the CSP specification provides a much-less commonly used method to control inline scripts called the script nonce. (Here’s a good tutorial from Google.) Script nonces are conceptually simple: the application tags each script with a one-time use number called a nonce, and the CSP header that comes along with the page lists all of the allowed nonces for the page. Before the browser runs a script, it checks that the nonce in the CSP header and the nonce on the page match.
Script nonces are hard to use in large-scale applications because different chunks of code, perhaps even running on different machines, can generate scripts and CSP headers, and if you can’t link the two together for each page load, user experience will be negatively affected.
Not surprisingly, very few major sites use script nonces. As usual, when you want to dig in to the details of how websites are served up, we’ll use Scott Helme’s excellent securityheaders.com. For any web site, we can print out the complete set of headers. Twitter is one of the few major sites that uses CSP nonces, which you can see by looking for the word “nonce” in HTTP headers Twitter is serving up. You can also make sure that the nonce changes on each load by refreshing the page and seeing the nonce value change.
My investigation of a few major sites showed that script nonces are not at all common (only Twitter uses them), and even CSP was a minority of big sites (only Twitter, Facebook, and YouTube even use CSP at all). If you’re having trouble implementing CSP, you’re not alone. You’re in the company of Google, Netflix, Reddit, Wikipedia, and Amazon. Need to start controlling scripts better? Give us a call!