Strict CSP

Content Security Policy can help 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.

Adopting a strict policy

To enable 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 policy.

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.

CSP policy example

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

Content-Security-Policy:
  object-src 'none';
  script-src 'nonce-{random}' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;
  base-uri 'none';
  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 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.

  • base-uri 'none' Disables <base> URIs, preventing attackers from changing the locations of scripts loaded from relative URLs. If your application uses <base> tags, base-uri 'self' is usually also safe.

  • 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.

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 check the security of your policy, use the CSP Evaluator.