Last updated at Mon, 02 Nov 2020 13:51:26 GMT

A Content Security Policy is a protocol that allows a site owner to control what resources are loaded on a web page by the browser, and how those resources may be loaded. This protocol was developed primarily to mitigate the impact of cross-site scripting (XSS) vulnerabilities. To understand exactly what this means, we need to dive into how modern websites and web applications work.

Most modern web apps consist of both static and dynamic content. An example of static content might be the copy for an “About” page that is hard-coded into HTML, or more likely, the general HTML structure of a navigation bar on a website. Dynamic content, on the other hand, is the portion of the site that is conditionally generated, typically from user-provided input. In a chat application, a username is dynamic content, as well as the text that encompasses a message. The user generates some input, then that input is dynamically inserted into the HTML document. Unfortunately, the browser has no idea whether a certain block of code or text was generated statically or dynamically. This is what opens the path for XSS attacks.

In a successful XSS attack, a user is able to supply input to an application that tricks the browser into executing code of the attacker’s choice. For example, if an application allows you to supply a username that is then rendered somewhere on the page, an attacker could supply a username of “”. When the browser takes that string and places it in the page’s source code, or Document Object Model (DOM), the browser interprets it as a valid JavaScript block, and executes it. This is an example of an XSS attack caused by inline script injection, but there are many different ways of injecting and executing JavaScript.

Another great example of content injection (although not technically XSS) is in 2014, Comcast came under fire for injecting advertisements into unencrypted browsing sessions of users connected to their free Wi-Fi hotspots. In this case, Comcast was intending to offset the cost of free internet hotspots by performing a man-in-the-middle attack where extra JavaScript was added to the content of a web page that caused advertisements to pop up. These ads were not approved by the website owners, and it raised serious security concerns about the ability to inject third-party content into browsing sessions. It should be noted that this particular vector for content injection was not possible for connections that were encrypted and is part of the reason I recommend that every website should require HTTPS, but that’s a conversation for another day.

So, as it turns out, there are many things that can influence what ends up being rendered in a user’s browser. There are several precautions you can take for things like validating user input and sanitizing data before rendering it, but that only gets you so far. Developers aren’t perfect, and they should assume that a malicious user will eventually find a way to bypass their protections and render arbitrary content. That’s where the Content Security Policy comes into play.

A Content Security Policy (CSP) is a series of commands that informs the browser of all the places the web app author anticipates content to be. Essentially, it acts as an allowlist of safe content for the DOM. While restricting inline JavaScript is probably the most important aspect of a CSP, it can also specify many other types of content restrictions, including sources of CSS, valid iFrame sources, valid types of plugins that should be supported or not (such as Flash), and approved websocket destinations. A CSP does not prevent XSS in that it does nothing to stop malicious input from being rendered in the DOM, but what it does do is mitigate the impact of an XSS attack by instructing the browser to not execute scripts that are not explicitly allowed.

What can a CSP do?

A Content Security Policy mostly restricts sources and types of content and where in the page that content can be presented, or rendered. In terms of preventing XSS, “inline JavaScript” tends to be the primary vector for malicious content. Inline JavaScript is when code is placed in a “