• Published
  • 7 min

Common Content-Security-Policy header errors and how to fix them.

Using a Content Security Policy on your web site or digital application is a great way to minimize risk of script injection, something that is considered to be one of the top three threats in the OWASP top ten list. However, implementing this header for a site can be challenging, specifically for sites with editorially controlled content.

In this blog we will examine various real-world situations when implementing the Content-Security-Policy (CSP) header. We will analyse the specific issues, explore potential solutions, and offer recommended approaches for each case. This will provide a practical understanding of how to address common CSP errors and strengthen your website's security.

What does the Content-Security-Policy header do?

The Content-Security-Policy (CSP) header is a security feature that helps prevent cross-site scripting (XSS) and code injection attacks. It allows developers to define rules for allowed content sources on a webpage. By restricting sources, CSP reduces the risk of malicious code execution. Browsers enforce the policy by blocking requests from unauthorized sources, providing an extra layer of security for websites and their users.

Initial setup

For our examples, we will use the following default Content-Security-Policy header: Content-Security-Policy: default-src 'self';. This configuration sets the default source to the current origin, restricting content to be loaded only from the same domain as the webpage.

We will use Microsoft Edge (Chromium) as the browser for our demonstrations. However, the principles discussed here are generally applicable to other modern browsers as well altough error messages might slightly differ in wording.

You can apply the concepts and techniques covered to any other tools or frameworks you prefer. The key takeaway is understanding how to address common CSP errors, regardless of the specific technology stack you are using.

1: Specific source directives and the default source directive.

Let’s add an embed video from YouTube to our page. This error will occur:

Refused to frame 'https://www.youtube.com' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'frame-src' was not explicitly set, so 'default-src' is used as a fallback.

Since we have not added https://www.youtube.com/ to our CSP header it will be blocked. The error message tells us that it first looked in the frame-src, and the default-src, which gives us two options.

Add it to default-src?

By adding the YouTube URL to the default-src, it will be picked up if the frame-src is not specified. It will also allow this origin on any source directive that is not explicitly configured.

Updated CSP header: Content-Security-Policy: default-src 'self' https://www.youtube.com;

Add it to frame-src?

By adding the YouTube URL directly to the frame-src, only origins specified in frame-src will be allowed for <iframe> and <frame> sources.

Updated CSP header: Content-Security-Policy: default-src 'self' ; frame-src https://www.youtube.com/;

This option is more secure, as it only allows the specified origin for <iframe> and <frame> sources, following the principle of least privilege.

In this guide, we will proceed with the recommended Option 2, which is adding the YouTube URL to the frame-src. Once added the video should be playable on your site. Note the trailing “/”, that means it will match any path from origin www.youtube.com.

2: Styles/Scripts elements

Styles and scripts can be added in multiple ways, via asset files, external URLs or inline. We will only focus on styling in the upcoming steps but the same principles apply for scripts as well.

Let’s start off by creating a custom styles.css and reference that in our page.

<link href="styles.css" rel="stylesheet" type="text/css">

When we run our page, no errors will show and our styles will be applied. This is because we have specified ‘self’ in the default-src, which means that we will allow the origin that we’re currently on.

Let’s add an external style reference to our page. For this example font-awesome via bootstrapcdn will be is used, but any other origin can be used if preferable.

<link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">

Once we run our site we will be faced with another error.

Refused to load the stylesheet 'http://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'style-src-elem' was not explicitly set, so 'default-src' is used as a fallback.explicitly set, so 'default-src' is used as a fallback.

Exactly as before our origin is blocked by the CSP and told that it looked for matching origins inside the style-src-elem directive and when not found it tried the default-src. As suggested in previous step, we want to be as specific as we can with our security. However, in this case we’re faced with additional complexity. Style and script have 3 directives each:

style-src-elem/script-src-elem

specifies valid sources for stylesheet <style> elements and <link> elements with rel="stylesheet”. If not specified style-src/script-src will be used instead.

style-src-attr/script-src-attr

specifies valid sources for attributes such as style and onClick. If not specified style-src/script-src will be used instead.

style-src /script-src

Covers both above. If not specified default-src will be used instead.

As of right now, safari does not have support for style-src-elem/script-src-elem or style-src-attr/script-src-attr which means that for compatibility we’re better off using style-src instead.

We could add http://netdna.bootstrapcdn.com/ to our style-src, but we also want to allow https://. By removing the scheme, we will allow both http and https to be used. Now we’re left with: netdna.bootstrapcdn.com/. Since we know we only want the font-awesome resource we can make our path more specific, instead of allowing all paths from netdna.boostrapcdn.com we can update our path to this: "netdna.bootstrapcdn.com/font-awesome/3.2.1/css/” to only allow resources starting from the specified path.

Once we add "netdna.bootstrapcdn.com/font-awesome/3.2.1/css/” to our style-src the error should disappear, and we’re faced with three new ones:

  1. Refused to load the font 'https://netdna.bootstrapcdn.com/font-awesome/3.2.1/font/fontawesome-webfont.woff?v=3.2.1' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'font-src' was not explicitly set, so 'default-src' is used as a fallback.
  2. Refused to load the font 'https://netdna.bootstrapcdn.com/font-awesome/3.2.1/font/fontawesome-webfont.ttf?v=3.2.1' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'font-src' was not explicitly set, so 'default-src' is used as a fallback.
  3. Refused to load the stylesheet 'http://localhost:5000/style.css' because it violates the following Content Security Policy directive: "style-src netdna.bootstrapcdn.com/font-awesome/3.2.1/css/". Note that 'style-src-elem' was not explicitly set, so 'style-src' is used as a fallback.

Let’s cover the first two ones first. The CSS that we have allowed is loaded and that CSS is referencing other types and origins, in this case fonts from https://netdna.bootstrapcdn.com/font-awesome/3.2.1/font/ so let’s add to our font-src as specified in the first two errors.

Now we’re left with the third error which is not related at all to font awesome, but to the style.css file we added in previous step. This is because we now have a style-src directive, so styles no longer fall back on the default-src as we previously did. To fix this we need to add ‘self’ to our style-src as well.

2.1: Inline styles/scripts

Inline styles or scripts are usually something we want to avoid. In a CSP perspective it’s always better to reference a file instead of using inline styles/scripts, but sometimes we’re forced into these scenarios by 3rd party modules.

Let’s add some inline style to our page.
<style>
    * { color: #e160ec; }
</style>

Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' netdna.bootstrapcdn.com/font-awesome/3.2.1/css/". Either the 'unsafe-inline' keyword, a hash ('sha256-Xs/WGawo0Vsamm0T1p79HVUyUhy4Mm6rLIwr6rIb2jE='), or a nonce ('nonce-...') is required to enable inline execution.

The error message gives us three option to fix this:

unsafe-inline

As stated in the name, this is the unsafe-option and should be avoided. This keyword will tell the CSP header that inline scripts/styles are fine, which it is not since if the site gets attacked with an injection attack, that code will be allowed to execute on our site.

Hash

A hash is more commonly used in SPAs where you have no possibility to refresh a "nonce" value on each request. But it can be very cumbersome to handle multiple hashes and keep them updated as inline code changes.

nonce

A nonce key is commonly used in server-side applications where we can send a unique nonce key on each new request. Note that a nonce key should be unique for each request and not predictable.

In this example we’ll use a nonce key to our csp style-src: ‘nonce-RANDOMKEYONEACHREQUEST’

<style nonce=’RANDOMKEYONEACHREQUEST’>
    * { color: #e160ec; }
</style>

Once the nonce value has been added, our inline script should be allowed.

In the scenario where we are forced into using unsafe-inline, most likely using a 3rd party code that we do not have direct control over. We will be faced with this error:

Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' netdna.bootstrapcdn.com/font-awesome/3.2.1/css/ 'nonce-f55f18e6-693c-4c6b-889d-e06155604072' 'unsafe-inline'". Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.

Since these two values are not compatible, we need to remove one of them, and since we are forced to use unsafe-inline we need to remove the nonce key from our CSP to properly execute our inline-styling.

Outro

In conclusion, this guide has provided insights into common Content-Security-Policy header errors and demonstrated how to address them effectively. By following these recommendations, you can enhance your website's security, protect against cross-site scripting and code injection attacks, and ensure a better user experience. As you continue to develop and maintain your site, always remember the importance of adhering to security best practices to keep your users and their data safe.