DEV Community

Robertino
Robertino

Posted on • Originally published at auth0.com

From Zero to Hero with CSP

Deploying CSP without disruptions is quite a challenge. This article offers you practical guidance on deploying CSP for modern web applications.


CSP is one of the most elaborate security policies in modern browsers. Besides acting as a second line of defense against XSS, CSP offers control over various types of content, outgoing connections, and the application's behavior. In this article, we elaborate on these features and provide you with a prioritized CSP deployment guide that will help you configure CSP in production.

Getting Started with CSP

In part 1 and part 2 of this series on CSP, we discussed the intricacies of using CSP as a second line of defense against XSS. In this third part, we look at deploying CSP in practice, starting from nothing. We also focus on additional features CSP has to offer beyond defending against XSS.

Before we dive in, let's set the scene. You have an application for which you'd like to configure a CSP policy. Awesome! Using the guidelines from the previous articles in this series, you have set up a CSP policy for your application, which brings you to a place known by every developer: "it works on my machine".

But what happens if you deploy this CSP policy in production? Will it work on your user's machines? Will it work on every browser? And more importantly, what happens if it doesn't work?

In essence, a lot of uncertainty with potentially disastrous consequences. A misconfigured CSP policy is likely to break the entire application, potentially for many users.

With that picture in mind, we're ready to dive in. Let's start by looking at one of the remarkable features of CSP: running a policy in report-only mode.

Deploying CSP in Report-Only Mode

You can tell a browser to run a CSP policy in report-only mode. This means that the browser will take your CSP policy, process it, and ensure that all application features are compatible with the policy. If the browser finds a violation, it will raise the necessary warnings and errors. However, unlike the examples we covered in the previous articles, the browser only reports the problem. The actual violation is not blocked.

Concretely, if the browser finds an unauthorized script block or script file, it will generate a warning, but it will not prevent the code from loading or executing.

To configure a report-only policy, the server sends the browser a CSP policy using the Content-Security-Policy-Report-Only header instead of the Content-Security-Policy header. The snippet below illustrates this configuration.

Content-Security-Policy-Report-Only: 
  script-src 'self';
  object-src 'none';
  base-uri 'self';
  report-uri /reporting/csp
Enter fullscreen mode Exit fullscreen mode

Report-only mode is the perfect way to test a policy without breaking the application. However, we're still missing a piece of the puzzle. Generating warnings and errors in the developer tools is helpful for local development, but how can you learn about errors generated in the user's browser? That's where the report-uri directive comes in.

You may have noticed that the earlier sample policy contained a report-uri directive. This directive includes a URL, which identifies an endpoint where the browser can send reports about policy violations. The snippet below shows a sample report from one of our demo applications.

{
   "csp-report":{
      "document-uri":"https://example.com",
      "referrer":"",
      "violated-directive":"script-src-elem",
      "effective-directive":"script-src-elem",
      "original-policy":"script-src 'self'; object-src 'none'; base-uri 'self'; report-uri /reporting/csp",
      "disposition":"report",
      "blocked-uri":"inline",
      "line-number":10,
      "source-file":"https://example.com",
      "status-code":200,
      "script-sample":""
   }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, the browser compiles a report in JSON format. The report contains information about the location of the violation, the policy that triggered the violation, and the type of violation. These reports are sent automatically when report-uri is enabled.

The reporting endpoint for handling CSP reports is straightforward. It accepts an incoming POST request with a JSON body and handles the data as desired. Typically, reports are logged in a data store for later consumption. Consumption of reports can be manual (e.g., through a dashboard) or automatic (e.g., analysis scripts). Note that most security information products have built-in support for CSP endpoints.

A final interesting tidbit about reporting is that you can ask the browser to include a sample of the inline code block that caused the violation. When 'report-sample' is added to the script-src directive, the browser will include the first 40 characters of the code block. This helps perform an investigation into the cause of the violation. If you can find the inline code block that matches the snippet, you know exactly where it came from. If it is legitimate, it should be authorized to load. Otherwise, CSP has likely stopped an attack, and you should investigate this further.

To summarize, report-only mode is the best way to try out your first CSP policy in the real world without causing any disruptions for your users. You can keep tweaking your policy in report-only mode until you're happy. Once everything looks good, you can deploy the policy in blocking mode using the regular Content-Security-Policy header.

Read more...

Top comments (0)