Avoiding Danger with CSP header: Content Security Policy

christina mitchell
4 min readFeb 10, 2020

Why do you need to care? Untrusted Code running wild on your domain doing nefarious things — that’s why!

In this post we talk about untrusted HTML and JavaScript. You may run user-supplied HTML, raw HTML from a backend service, or HTML templates. In each case, you should take precautions.

Perhaps you’re using an externally sourced chatbot in your application or you’d like to allow an customer to create their own advertisement in creating their own HTML to run on your site. While these can be useful, they can also be dangerous.

We have a saying in Security: “it’s not if something can be compromised, but when.” For the most part, 3rd party Javascript tools run directly on our domain as a snippet or as a self-building script. When that tool gets compromised, your site can be compromised, and the source of the attack will be hard to determine since the tool is running on our own domain. If an attacker uses a compromised plugin that is running on our own domain to add a cryptominer to your page, we’d have a harder time figuring out what was happening.

Content Security Policy (CSP) can help us prevent such situations. With it, we can establish accept lists that determine where scripts can call out to.

CSP

This identifies what origins can run on your page in an attempt to minimize Cross Site Scripting (XSS), clickjacking and 3rd party data exfiltration. As we integrate with third party tooling, scripts, trackers etc., it becomes more challenging to protect sites from these kinds of attacks. It will be harder to determine when a script is compromised. With CSP we can restrict attacking scripts from phoning home.

— Security recommendations —

Recommendation 1: Use content security policy (CSP)

Use the header Content-Security-Policy:

Default-src 'self';

Refer to this OWASP cheat sheet for a reference of default policies to use.

CSP best practices

Be specific with your accept list. Using *.yourdomain.com is not specific enough and can allow other domains to talk to your endpoint. Especially if you have a large site, be incredibly specific. Instead, use subdomain.yourdomain.comas a better protection.

CSP patterns to avoid

  • Avoid general declarations of resource domains in your default-src:
  • *.domain.com

Instead, use: form-src, img-src, script-src, connect-src:

Like this example: default-src: https://www.example.com: ‘self’; img-src: http://stuff.com

Avoid the following CSP directives:

  • policy set broadly: domain.com
  • Unsafe-inline: Allows JavaScript to run. Instead, turn the code into external JavaScript files.
  • unsafe-eval: eval() or SetTimeout().Try promises in JS instead. Generally we say not to include the unsafe-inline and unsafe-eval however some policies have these directives included to avoid refactoring code in case they use SetTimeOut or setInterval, or inline scripts for older scripts or from a library. Therefore if you’re making a fresh product you can avoid these directives from the beginning.

Recommendation 2: Limit the set of allowed HTML

Especially when allowing user-supplied HTML, you can limit the scope of HTML the user can enter:

  • Accept only benign formatting tags such as <b>, <li>, and <i>. Keep the list of allowed tags small and simple.
  • Remove all attributes. Attributes can be used to inject JavaScript.
  • Avoid links and iframes in your allowed HTML.

Recommendation 3: Sanitize the HTML you allow

Use a sanitizer library to help ensure the safety of the HTML your content runs, whether user-supplied or originating from a third party. Libraries include:

  • bleach
  • sanitize-html
  • dom-purify

True security all-stars sanitize HTML input after it is entered by the user and before it is rendered. If you only sanitize once, however, do it last.

Recommendation 4: Use iframes

Using an iframe with the “sandbox” attribute allows you to isolate your untrusted content from the rest of the page, minimizing the damage it can do if malicious code is run.

  • Method: Inline — src="data:"
    Places HTML directly in the iframe. The data is no longer from the same origin and the CSS parent will no longer apply.You can no longer use relative paths. Paths must be absolute.
  • Method: External — src="https://external.com" Uses a different origin, preventing JavaScript execution. Requires a new domain, a new app, and creates overhead.

CSP things to note:

  • CSP — isn’t perfect. Not all browsers use it. And it doesn’t apply to anchors.
  • CSP is not a full fix for XSS — you need to escape your content in the app or it’s still vulnerable.
  • However it is an exceptional tool that can help you, and is worthwhile using!

Further Reading:

--

--