5 years ago
Stuart Larsen #article
Content Security Policy was built to combat a prolific web vulnerability known as Cross Site Scripting, or XSS. (More info). But CSP also offers protections besides just (defense in depth) protection against XSS.
This article covers some of those additional features.
Both 'block-all-mixed-content' and 'upgrade-insecure-requests' deal with content loaded over insecure channels (http/ws).
As of recently major browsers block security-sensitive resources (also called 'active mixed content' or 'blockable content') from being loaded from an insecure origin when currently on a secure origin. So stuff like javascript and stylesheets could potentially be blocked.
So right now, if you are on https://
securewebsite.com and try to load http://
cdn.js.com/jquery.js it will fail since the request is http. This is pretty cool and a huge leap forward for making the web more secure.
Non-security sensitive resources (also called 'passive mixed content', or 'optionally blockable content)' still load. This is stuff like images, videos, audio. Stuff that can't harm or interact with the rest of the website. It's still good to upgrade it though. While more difficult to pull off, you could imagine a scenario where swapping button images could cause someone to take the wrong action. (Or you could just be a troll and person-in-the-middle in some lewd content).
Figure 1: Mixed Content Warning
upgrade-insecure-requests will simply convert any insecure resource to the secure resource counterpart. So an image loaded from http://
image4all.com/cats.png will be converted to https://
image4all.com/cats.png. If the https:// equivalent doesn't exist, the request will fail.
This probably sounds similar to HSTS (HTTP Strict Transport Security), and it is very similar, but there are differences. A big difference being that the upgrade-insecure-requests will only apply to elements on the specific page that returned the 'upgrade-insecure-requests' header. HSTS will apply on the initial page load. HSTS also applies to a domain, whereas 'upgrade-insecure-requests' applies to all resources on the web page.
(For the technically sound readers, it's also cool to note that upgrade-insecure-requests will work through multiple levels of iframes.)
To apply 'upgrade-insecure-requests' just include it in your CSP like a normal directive.
block-all-mixed-content is even simpler. It just blocks all insecure requests. (It also works through multiple levels of iframes) To apply 'block-all-mixed-content' just include it in your CSP like a normal directive.
The frame-ancestors directive can be used as a substitute for the HTTP header X-Frame-Options (XFO), a protection against clickjacking, (sometimes called ui redressing attack).
If you're not familiar with click jacking, the key insight is that it's possible to create a transparent iframe that is still interactable. So on https://myevilsuperaddictivegame.com I could embed a transparent iframe to bank.com, so while you think you're typing in random numbers as part of the game, you're actually typing in my bank account number, 1,000,000 and then clicking send. frame-ancestors is similar to X-Frame-Options, except frame-ancestors is better for two reasons:
When both frame-ancestors and XFO are seen on the same request, the browser will follow frame-ancestors.
Using CSP you can define where HTML <form>s are allowed to submit data.
This has a couple of uses, the obvious is maybe an attacker could inject a form into a web page that submits some data somewhere. Maybe it's used to redirect to a page that looks similar to the original page and then attempts to phish credentials or something.
The less obvious is in the form of dangling markup injections. These attacks are described in more detail in one of my all time favorite articles: Postcards from the post-XSS world. But tl;dr; there's a few attacks where you could attempt to steal CSRF tokens (or other sensitive inline material) by constructing forms that "eat up" a bunch of HTML and then the "post" that html to an endpoint as a form parameter. (Or if it's a CSRF token, it just treats it like a normal form input).
A very neat feature of <iframe>'s is the 'sandbox' attribute. You can use it to severely lock down what a page is allowed to do.
With Content-Security-Policy you can now do that to any website, not just <iframe>'s.
(One of the very cool features of an iframe's sandbox is that it treats content like it came from some other random origin (meaning it won't have access to cookies/localstorage etc). Combine this with iframe's srcdoc attribute and you have a very nifty way to embed untrusted content. But that's not as useful for CSP)
There's a bunch of directives, I've listed a couple of the cool ones here, but the full list can be found on the mozilla docs.
Value | Description |
---|---|
allow-forms | The webpage can include <form>s |
allow-popups | The webpage can use window.open, target="_blank" and other popups |
allow-scripts | The webpage can execute scripts (javascript) |
allow-top-navigation | The webpage can redirect to different pages |
There's also some stuff for downloads, orientation locks, pointers, presentation mode, etc.
If you specify just 'sandbox' the page won't execute javascript, no forms, no nothing. Just pure clean HTML.
Sometimes you have to allow object-src. A common example was for allowing flash to copying data to clipboard. (Now thankfully there are javascript APIs for that).
But, including one object-src includes a bunch of nasty stuff you're probably don't want to also include, like shockwave, and silverlight, and applets. So instead you can specifically say what type of plugins you support. (Although hopefully it's none).
There's a cool feature of script tags and style tags where you can do integrity checking on the resource before it's executed. Basically you attach a hash of the contents of the script that is about to be remotely loaded. Then when the browser downloads the script it'll make sure the hash matches (so you know the remote script didn't change).
SRI is completely legit and ready to go.
<script src="https://code.jquery.com/jquery-2.1.4.min.js"
integrity="sha384-R4/ztc4ZlRqWjqIuvf6RX5yb/v90qNGx6fS48N0tRxiGkqveZETq72KgDVJCp2TC"
crossorigin="anonymous"></script>
There's also a feature of CSP where you can specify "require-sri-for" and 'script' and/or 'style'. Which will mandate SRI for those resources on a website.
But it is behind feature flag on chrome, and not supported by mozilla (anymore). Maybe in the future.
There's a third type of XSS that CSP doesn't fully address, this is DOM based XSS. Trusted-types is a proposal where you have to specifically tag resources and their types before they can fed into certain browser functions. (These browser functions are xss-sinkable, like innerHTML).
It's not supported yet, but should be exciting to see. Hopefully in the future you can use CSP to enable trusted-types, and even only allow specific trusted-type "templates".
This is still in the draft, but it's an interesting idea where you can specify the allowed locations where a page can navigate to (<a> tags, window.location, forms, etc).
This is useful because even with CSP, an attacker can inject HTML. So an attacker could inject content that looks like it's part of the original page, put in some <a> tags, and then have those <a> tags redirect to a different phishing website that looks exactly the same as the original in hopes of tricking the user to re-type their password or something.
Well I hope you had a good time learning about the other security features of CSP. If you have any questions or comments, I'd love to chat. stuart@csper.io.
Stay up to date with the latest Content Security Policy news, product updates, discounts, and more!