Security Best Practices

Content Security Policy – All You Need to Know

What is Content Security Policy?

Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement to the distribution of malware.

Unsafe Inline or Unsafe Eval

Inline JavaScript and CSS are often used on websites but they are also dangerous. They’re the easiest way for a hacker to create an XSS attack. Therefore, to allow them you must add 'unsafe-inline' to the directive you want to allow them for. This is to make sure you understand, what you’re doing isn’t recommended.

A common CSS pattern is to inline your most important CSS that renders your ‘above fold content’ with <style> tags. This can help decrease the perceived rendering time. With HTTP/2, it can be argued against doing this as it tends to be slower. If you do choose to use inline scripts, you have three options.

  1. Get a SHA-256 hash of the script & add it to our CSP. Chrome’s dev tools will even generate a SHA-256 for you in the console when it displays the CSP error. Adding it to our current CSP example would look like this:
Content-Security-Policy-Report-Only: default-src 'none'; form-action 'none'; frame-ancestors 'none'; style-src 'self'; script-src 'self' cdnjs.com sha256-c2u0cNUv1GcIb92+ybgJ4yMPatX/k+xxHHbugKVGUU8=; img-src 'self';
  1. Generate a unique nonce by your server for each inline script. This means each server request has to generate a new nonce. You would add it to your CSP the same way as a SHA-256, nonce-47c2gtf3a1. You also need to add it to the script tag: <script nonce="47c2gtf3a1">. It’s rare to see nonces used as they are rather inconvenient to implement.
  2. Allow inline scripts by adding 'unsafe-inline' to your policy. This allows inline scripts, which weakens your CSP & allows XSS attacks.

Preventing secure sites from loading images or media over HTTP

The CSP reporting mechanism can be used to track the mixed content on your site; and the enforcement policy, to protect users by upgrading or blocking mixed conten. You can enable these features for a page by including the Content-Security-Policy or Content-Security-Policy-Report-Only header in the response sent from your server. Additionally, you can set Content-Security-Policy (but not Content-Security-Policy-Report-Only) using a <meta> tag in the <head> section of your page. See examples in the following sections.

CSP is useful for many things outside of its mixed content uses. Information about other CSP directives is available at the following resources:

Finding mixed content with content security policy

You can use content security policy to collect reports of mixed content on your site. To enable this feature, set the Content-Security-Policy-Report-Only directive by adding it as a response header for your site.

Response header:

Content-Security-Policy-Report-Only: default-src https: 'unsafe-inline' 'unsafe-eval'; report-uri https://example.com/reportingEndpoint

Whenever a user visits a page on your site, their browser sends JSON-formatted reports regarding anything that violates the content security policy to https://example.com/reportingEndpoint. In this case, anytime a subresource is loaded over HTTP, a report is sent. These reports include the page URL where the policy violation occurred and the subresource URL that violated the policy. If you configure your reporting endpoint to log these reports, you can track the mixed content on your site without visiting each page yourself.

The two caveats to this are:

  • Users have to visit your page in a browser that understands the CSP header. This is true for most modern browsers.
  • You only get reports for pages visited by your users. So if you have pages that don’t get much traffic, it might be some time before you get reports for your entire site.

For more information on CSP header format, see the Content Security Policy specification.

If you don’t want to configure a reporting endpoint yourself, https://report-uri.io/ is a reasonable alternative.

Upgrading insecure requests

One of the newest and best tools to automatically fix mixed content is the upgrade-insecure-requests CSP directive. This directive instructs the browser to upgrade insecure URLs before making network requests.

As an example, if a page contains an image tag with an HTTP URL:

<img src="http://example.com/image.jpg">

The browser instead makes a secure request for https://example.com/image.jpg, thus saving the user from mixed content.

You can enable this behavior either by sending a Content-Security-Policy header with this directive:

Content-Security-Policy: upgrade-insecure-requests

Or by embedding that same directive inline in the document’s <head> section using a <meta> element:

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

It is worth noting, that if the resource is not available over HTTPS, the upgraded request fails and the resource is not loaded. This maintains the security of your page.

The upgrade-insecure-requests directive cascades into <iframe> documents, ensuring the entire page is protected.

Blocking all mixed content

Not all browsers support the upgrade-insecure-requests directive, so an alternative for protecting users is the block-all-mixed-content CSP directive. This directive instructs the browser to never load mixed content; all mixed content resource requests are blocked, including both active and passive mixed content. This option also cascades into <iframe> documents, ensuring the entire page is mixed content free.

A page can opt itself into this behavior either by sending a Content-Security-Policy header with this directive:

Content-Security-Policy: block-all-mixed-content

Or by embedding that same directive inline in the document’s <head> section using a <meta> element:

<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">

The downside of using block-all-mixed-content is, perhaps obviously, that all content is blocked. This is a security improvement, but it means that these resources are no longer available on the page. This might break features and content that your users expect to be available.

Sources:

  • CSP description from the website here.
  • Unsafe inline content from the website here.
  • CSP to prevent loading media over HTTP from the website here.

Was this helpful?