Strict CSP

Content Security Policy can protect your application from XSS, but in order for it to be effective you need to define a secure policy. To get real value out of CSP your policy must prevent the execution of untrusted scripts; this page describes how to accomplish this using an approach called strict CSP. This is the recommended way to use CSP.

Example

A production-quality strict policy appropriate for many applications is:

Content-Security-Policy:
  object-src 'none';
  script-src 'nonce-{random}' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;
  report-uri https://your-report-collector.example.com/

Let's look at the properties of this policy as interpreted by a modern browser:

  • object-src 'none' Prevents fetching and executing plugin resources embedded using <object>, <embed> or <applet> tags. The most common example, nowadays, is Flash.

  • script-src nonce-{random} 'unsafe-inline' The nonce directive means that <script> elements will be allowed to execute only if they contain a nonce attribute matching the randomly-generated value which appears in the policy.

    Note: In the presence of a CSP nonce the unsafe-inline directive will be ignored by modern browsers. Older browsers, which don't support nonces, will see unsafe-inline and allow inline scripts to execute.

  • script-src 'strict-dynamic' https: http: 'strict-dynamic' allows the execution of scripts dynamically added to the page, as long as they were loaded by a safe, already-trusted script (see the specification).

    Note: In the presence of 'strict-dynamic' the https: and http: whitelist entries will be ignored by modern browsers. Older browsers will allow the loading of scripts from any URL.

  • 'unsafe-eval' allows the application to use the eval() JavaScript function. This reduces the protection against certain types of DOM-based XSS bugs, but makes it easier to adopt CSP. If your application doesn't use eval(), you can remove this keyword and have a safer policy.

  • report-uri https://your-report-collector.example.com/ causes all violations to the policy to be reported to the supplied URL so you can debug them.

When such a policy is set, modern browsers will execute only those scripts whose nonce attribute matches the value set in the policy header, as well as scripts dynamically added to the page by scripts with the proper nonce. Older browsers, which don't support the CSP3 standard, will ignore the nonce-* and 'strict-dynamic' keywords and fall back to [script-src 'unsafe-inline' https: http:] which will not provide any protection against XSS vulnerabilities, but will allow the application to function properly.

There are several variations of this policy which can be useful. For example, if desired, the application could allow some whitelisted Flash resources or protect itself from being framed by untrusted domains (frame-ancestors *.google.com). Additional directives could be used to restrict the sources of stylesheets (style-src), frames (frame-src), and other resources, but they don't provide any significant extra protection against XSS.

For a more in-depth overview of the security properties of CSP and an explanation of the advantages of using a strict policy, see the research paper. To analyze how secure your policy is, use the CSP evaluator.

Adopting a strict policy

To use a strict CSP policy, most applications will need to make the following changes:

  • Add a nonce attribute to all <script> elements. Some template systems can do this automatically.
  • Refactor any markup with inline event handlers (onclick, etc.) and javascript: URIs (details).
  • For every page load, generate a new nonce, pass it the to the template system, and use the same value in the Content-Security-Policy response header.

Adopting CSP guides you through this process in more detail, including code examples, and explains how to use tools to help with any necessary refactoring.