Skip to main content
U.S. flag

An official website of the United States government

The .gov means it’s official.
Federal government websites often end in .gov or .mil. Before sharing sensitive information, make sure you’re on a federal government site.

The site is secure.
The https:// ensures that you are connecting to the official website and that any information you provide is encrypted and transmitted securely.

Content Security Policy

What is Content Security Policy?

Content Security Policy (referred to as CSP in the rest of this guide) is a security measure designed by the W3C (World Wide Web Consortium) to mitigate the likelihood of Cross-Site Scripting (XSS) attacks and data injection. It is designed to be used in conjunction with other security practices currently recommended for web development.

It can be enabled on either client- or server-side, and is unobtrusive in unsupported browsers — that is, browsers that don't support CSP will ignore its directives and load the page as normal.

CSP is supported by the current versions of all modern desktop browsers: Safari, Chrome, Firefox, and IE Edge. It is also supported in recent versions iOS Safari and Chrome for Android.

Unfortunately, support for numbered versions of IE is essentially zero, with no support for IE < 10 and only two directives supported in IE 10+.

All of the above supported browsers support CSP 1.0, with 100% support for 2.0 in Webkit/Blink browsers, and partial, but very good, support in Firefox. CSP 2.0 has all the features of 1.0, with several additional directives and support for inline <script> and <style> tags (see Caveats).

Usage

CSP is straigtforward to implement, and supports providing a policy server-side via HTTP header or client-side via a <meta> tag.

Policies

The most important aspect of CSP is the policy itself, which is written as a string of directives. Directives describe how the browser should handle loading different content types. These directives are represented as a ; delimited key-value pair.

The values in this pair can either be keywords, schemes, mime-types, or urls. Keywords are always enclosed in single quotes, while all other values are left unquoted. Multiple values may be supplied in a single directive, they are always separated by a space.

A comprehensive list of values and directives can be found at the Content Security Policy cheatseet.

In general, your policy will restrict loading of content to known sources, and a usable sample policy could look something like this:

"default-src 'self'; script-src https://facebook.com; child-src https://youtu.be; object-src 'none';"

Let's break this down:

  default-src self : Only load content from the current
    origin, exluding subdomains

  script-src https://facebook.com : Allow
    scripts (e.g. `Like` button code) from Facebook
    to load over HTTPS

  child-src https://youtu.be : Allow embedded content
    from YouTube over HTTPS

  object-src none : Prevent Flash content from loading

The default-src directive should always be defined! This directive acts as a fallback for all other *-src directives that are not defined within in the policy or are unsupported.

It might be useful to test your policies before letting them loose on your users. To do this, use the Content-Security-Policy-Report-Only HTTP header. Combined with the reporting information in the next section, you can monitor the kinds of content your user's are encountering and tweak the your policy accordingly.

Reporting

CSP can also be configured to send reports to an endpoint you control when content that violates your policies is encountered.

To do this, use the report-uri directive, passing it a fully qualified URI, e.g. https://my-public-site.gov/reports/csp. Now, each time content from an invalid source is encountered, your browser will POST a JSON payload to the provided URI.

Here is an example, from the MDN article linked in Further Reading

{
  "csp-report": {
    "document-uri": "http://example.com/signup.html",
    "referrer": "",
    "blocked-uri": "http://example.com/css/style.css",
    "violated-directive": "style-src cdn.example.com",
    "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports"
  }
}

This data can of course be mixed with other request metadata, like IP address or browser User-Agent, and fed into whatever log processing system your app has in place.

Reporting can only be enabled via HTTP header, not inside a <meta> tag!

Client-side implementation

To implement CSP on the client, add a <meta> tag to your web site's <head>. Your policy will be a doubled-quoted string placed inside the content attribute of the tag.

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

You're done!

Server-side implementation

To include a CSP headers on the server, simply return a Content-Security-Policy: {my-policy-string} HTTP header in your web responses.


Although a basic CSP policy is relatively easy to write, you might find it easier to use a server-side library to define your policies declaratively. Some well-known and actively maintained libraries include:

Note that this list is neither exhaustive nor prescriptive. These libraries are included in this guide to give you a sense of the capabilities that might be included in a library that works with the CSP header.

Caveats

A major caveat is that CSP, by default, prevents developers from adding inline <style> and <script> tags, and from specifying JavaScript behavior or CSS style attributes directly on DOM elements. This isn't a bad thing, as current best practices in front-end development discourage the use of these patterns.

However, there are scenarios in which you may want to use an inline content tag, such as including a Google Analytics initialization script. For these cases, CSP allows the user to supply a nonce attribute to the inline script: <script nonce=GHDGsfsd83hfdfFD3>...javascript here...</script>. Then, in your policy, script-src 'nonce-GHDGsfsd83hfdfFD3'. Nonces must be regenerated on each request. Additionally, CSP 2.0 allows you to generate a SHA hash of the script content, and pass that to the script-src directive as 'sha-{content-sha}'. You don't need to use a nonce attribute if your content is hashed.

Another potential issue is third-party libraries that automatically inject JavaScript and CSS into your HTML. If your project utilizes a library that does this, the only guaranteed solution is to use the unsafe-inline value when setting the script-src directive; this obviously defeats the purpose of having a CSP for your JavaScript.

If you must load external scripts inline and are not allowed to use the unsafe-inline keyword, you could also make a SHA hash of the script being included, and allowlist that in your content security policy.

This technique will allow those scripts to load, with the following caveats:

  • Each the time the third-party script changes, a new hash will have to be computed, and your policy's script-src allowlist will need to be updated
  • Inline the SHAs of multiple scripts adds bloat to the policy, and increases the number of bytes needed to transmit the header to the browser.

As each project has its own needs, you should always perform your own research on a per-project basis to determine the best way to handle third-party scripts!

Further reading

The information contained is this guide is only a primer, and was sourced from the following articles:

The following links are fairly old, but pretty short and worth skimming

18F Engineering

An official website of the GSA’s Technology Transformation Services

Looking for U.S. government information and services?
Visit USA.gov