Why It's Bad to Use 'unsafe-inline' in script-src

5 years ago

Stuart Larsen #article


This article covers why 'unsafe-inline' in a Content Security Policy is a bad idea, and what can be done instead of using 'unsafe-inline'.

Background

'unsafe-inline' within script-src is the most common security misconfiguration for Content Security Policy (CSP). According to google's research, 87% of websites that deploy content-security-policy use 'unsafe-inline' within their script-src.

Of the XSS protection policies, 87.63 % employed the ’unsafe-inline’ keyword without specifying a nonce, which essentially disables the protective capabilities of CSP.

https://research.google/pubs/pub45542/

If you're curious if your domain is using 'unsafe-inline', check out Csper Evaluator.

The Problem CSP is trying to solve

A full description on the problem CSP is trying to solve can be found here: An Introduction to Content Security Policy, but following is a short introduction.

Content Security Policy was built to combat a prolific web vulnerability known as Cross Site Scripting (XSS). XSS is the unwanted execution of javascript on a web page. An attacker injects javascript into a web page they don't control, so that other users of the website also run the malicious javascript. The attacker can use this to their advantage to perform a variety of nasty actions such as taking over accounts, performing actions on behalf of the user, or defacing the website.

How CSP tried to solve it

One common element of the top two types of XSS (reflected, stored) is that the attacker's javascript is directly injected into the page's HTML. An example XSS could look like something similar to the followings:

<script>doEvilThings()</script>

or

<img src=x onerror="doMoreEvilThings()"/></p>

Content Security Policy is a security mechanism to block attacker injected scripts. Content Security Policy disallows ALL inline javascript (and requiring you to make whitelists of external URLs that you load javascript from.)

So when using Content Security Policy, all javascript must come from those trusted sources. But since we've limited all javascript to only come from trusted URLs, you know that even if an attacker injects an XSS into your web page, it won't execute.

Why 'unsafe-inline' in script - src is bad

When you put 'unsafe-inline' in the script-src of a content security policy, you are effectively disabling the most important part of content security policy. Content Security Policy was built to combat Cross Site Scripting by requiring that you can only load javascript from a specifically trusted origins. But when you put in 'unsafe-inline' you are allowing javascript back into the HTML, which makes XSS possible again.

Technically there are other reasons for rolling out CSP, but for most websites it's to prevent XSS. So if 'unsafe-inline' is included, all that time spent was pretty much worthless. If an attacker is technical enough to find an XSS on your website, they're technical enough to abuse an 'unsafe-inline' in your policy.

What can be done instead of unsafe-inline

There's a couple of options:

  • (Recommended) Move javascript into its own file
  • Switch to Report-Only and use a report-uri service
  • Hash / Nonce

The best way is to move the inline javascript into a .js file and then include it on your webpage. Then it is no longer inline.

For example if you had something similar to:

<button onclick="doTheThing()" id='mySpecialButton'>Do The Thing</button>

You could instead put it in an app.js as:

document.getElementById("mySpecialButton").addEventListener("click", doTheThing);

Moving all inline javascript to .js files is the best, most secure, and long term solution. But it's also the most work.

For help on moving inline resources, check out the Csper docs: Removing Inline Resources.

Switch to Report-Only and use a report-uri service

This option is the fastest, but only gives you insight into the XSS's happening on your website (and will result in some noise). But, it's better than doing nothing.

You can change your policy to instead be in report-only mode, remove the 'unsafe-inline', and use a report-uri (such as Csper) to monitor/alert on new types of reports that you've never seen before. These new reports could be an indication that (1) something new happened on the website (2) there's an attack happening on your website.

You'll loose the automatic blocking feature of Content Security Policy, but you'll get insight of the attacks on your website. Now you can take action to fix the underlying issue, which is the most important.

Hash / Nonce

CSP also supports the concepts of hash/nonce. You can instead include either a hash of the javascript in your content-security-policy, or include a nonce in your content-security-policy and attach that nonce to all pieces of inline javascript.

If you use nonce-src, it's an all or nothing. Any usage of nonce will make the browser ignore 'unsafe-inline' (for compatibility reasons).

Both of them work, but if you're willing to go through the effort, might as well just move the inline javascript to its own file.

Conclusion

I hope this has been insightful, and that if you're using 'unsafe-inline' you'll consider switching. If you have any questions, feel free to reach out to stuart@csper.io!

Subscribe for updates?

Stay up to date with the latest Content Security Policy news, product updates, discounts, and more!