Content-Security-Policy

From IndieWeb


Content-Security-Policy (abbreviated CSP) is an HTTP directive that a site can use to restrict what external resources are retrieved by a browser, to mitigate some XSS and injection attacks.

Why

AT&T hotspot ad injection into http sites: http://webpolicy.org/2015/08/25/att-hotspots-now-with-advertising-injection/

How to

Send CSP header

Configure your webserver to send a

  • Content-Security-Policy

HTTP header (e.g. for Apache, update your .htaccess) according to the policy you prefer (see Examples section below for options to consider for your site.

Test your CSP

Check that your server is sending the right CSP:

  1. Go http://www.whatsmyip.org/http-headers/
  2. Enter your domain (or a post permalink) into the big white text box
  3. click "Get Headers"
  4. scroll down to "HTTP Response Headers"
  5. you should see an entry for "Content-Security-Policy" in the left column, and on its row in the right column, it should show exactly what you configured your server to send.

Then load your site/permalinks in whatever browsers you can run, and check their View/Tools/Developer (Web Console, Show Error Console, Developer Tools) for errors, in particular for anything being blocked that you wanted to load.

Examples

Only Resources From Same Domain

Only allow external resources from the precise same domain, no subdomains:

Content-Security-Policy: default-src 'self'

Include subdomains:

Content-Security-Policy: default-src 'self' *.example.com

Where example.com is your trusted top level personal domain.

Allow Only Media From Anywhere

Allow images/audio/video embeds from anywhere, but scripts, style sheets, iframes etc. only from same domain:

Content-Security-Policy: default-src 'self'; img-src *; media-src *
Why img-src *
Embedding images from external domains is a fairly common practice, e.g. icons of people in reply-contexts, comments, or photos hosted on other domains (e.g. silos), etc. Alternatively if you proxy all your images through a subdomain on your site (i.e. to uplevel them to https), then you could restrict img-src to that subdomain (with https).
Why media-src *
Also if you autolink your notes, e.g. with the CASSIS auto_link() function, then you're likely also auto-embedding as part of that and thus turning any common audio file extension link into an <audio> and similarly with video file extension links and <video>. Since those audio/video file links can be from any domain, the media-src * makes sense.

Allow Anywhere Media Whitelist Iframes

Allow images/audio/video embeds from anywhere, iframes from an https whitelist, and scripts, style sheets only from same domain:

Content-Security-Policy: default-src 'self'; img-src *; media-src *; child-src https://player.vimeo.com https://www.youtube.com
Why child-src https://player.vimeo.com https://www.youtube.com
Again if you use an autolink function that auto-embeds, then it's likely turning every YouTube and Vimeo link into an iframe to embed players for those videos. That child-src directive in the example explicitly allows loading of external iframes only over https only from those specific domains (whitelist).

IndieWeb Examples:

IndieWeb Examples

Tantek

Tantek Çelik on tantek.com since 2015-08-28 has used the following CSP (updated 2016-108) on his home page and post permalinks:

Content-Security-Policy: default-src 'self'; img-src *; media-src *; script-src 'self' 'unsafe-inline' https://platform.twitter.com; style-src 'self' 'unsafe-inline'; frame-src *; child-src *;

Based on the Allow Anywhere Media Whitelist Iframes example above, with the following additions for the following reasons:

  • script-src 'self' 'unsafe-inline' - because I still have some inline scripts that I didn’t want to take the time to fix before, but now have motivation to do so.
    • with https://platform.twitter.com to allow Twitter webaction tweet button with tweeted count to work on my article posts.
  • style-src 'self' 'unsafe-inline' - because I still have some inline style sheets and style attributes that I didn’t want to take the time to fix before, but now have motivation to do so.
  • frame-src - for backcompat with Safari 8.0.7 (and before?) which is latest version on OSX 10.10.4, and Microsoft Edge (tested as of 2015-08-28 Microsoft Edge build).
  • child-src *; (as of 2016-108) necessary to support indie-config. Previously: child-src platform.twitter.com - to also allow Twitter tweet buttons as noted above.
    Note: child-src platform.twitter.com instead of child-src https://platform.twitter.com (which would be better) because the current platform.twitter.com/widgets.js, even if referenced via https, has one spot where it does an iframe embed that is parent page protocol relative, and thus ends up embedding an http iframe. To be able to use only the child-src https, I need to either:
    • Get Twitter to fix platform.twitter.com/widgets.js to always embed its iframe with https, OR
    • Switch my site to using https so the protocol relative iframe src will also be https, OR
    • Drop the "Tweet" button from my article posts (in which case I could drop the platform.twitter.com from the child-src and frame-src completely.)

Shane Becker

Shane Becker on veganstraightedge.com using Dark Matter since 2016-02-24 has used the following CSP on his website

Content-Security-Policy: default-src 'self' http:; child-src *; frame-src *; img-src * data:; media-src *; script-src 'self' platform.instagram.com ; style-src 'self' 'unsafe-inline'

Based on the Allow Anywhere Media Whitelist Iframes and Tantek Çelik's examples above, with the following additions for the following reasons:

  • default-src 'self' http: - My software (Dark Matter) adds http: or https: to match whatever the site uses (based on a setting that is user changeable to match their site's scheme)
  • child-src * - Both of these are set to * mainly because I couldn't get this work with a list. I plan change this to an explicit list when I figure out what my code's problem is.
  • frame-src * - Both of these are set to * mainly because I couldn't get this work with a list. I plan change this to an explicit list when I figure out what my code's problem is.
  • img-src * data: - I include data: because I'm using some SVG from a data://url in addition to SVG img[src=url.svg]
  • script-src 'self' platform.instagram.com - I don't include 'unsafe-inline' because I don't already have any inline script blocks that I need to support. And I don't want to support them going forward. I don't include https://platform.twitter.com because I don't have Twitter buttons on my site. I also added platform.instagram.com because I use Instagram's embed code.
    • I'll add more domains to this whitelist for auto-embeds in Notes.
    • I'll eventually remove instagram in particular by building an auto-embed that doesn't use Instagram's JS/iframe.
  • style-src 'self' 'unsafe-inline' - I also include 'unsafe-inline' because post specific styles are served up into style tags. And I don't see a meaningful security hole by allowing CSS in style tags.

Bridgy

Bridgy has used the following CSP since 2016:

Content-Security-Policy: script-src https: localhost:8080 my.dev.com:8080 'unsafe-inline'; frame-ancestors 'self'; report-uri /csp-report;

... add your site too! ...

Add your site, when you started using a CSP, and preferably copy/paste it here inline and explain any changes from the common practices in the Examples section.

FAQ

Why bother if attacker can hack CSP too

Q: On an HTTP (not HTTPS) connection, an attacker can theoretically either strip your CSP header, modify it (to allow their junk), or replace it entirely with one of their own. Why bother adding a CSP since it too can be attacked?

A: In short, Defense in Depth.

Longer:

Just because an attacker is willing to use one mechanism, it doesn’t mean they are willing (or even necessarily capable - even if you think it is "obvious") to use another mechanism.

In the case of ATT wifi hotspots injecting ads, it's one thing to just add ads to the page, but it's quite different in quality and nature to remove/change HTTP headers, especially one with security in its name, hence they are unlikely to do so. That being the original use-case we were solving for, we can consider it solved.

And even if an attacker is willing to workaround multiple mechanisms, they are having to spend more time doing so, which in some cases may be enough to thwart an attack, especially if time/timing is an issue.

For more on the general concept see: Wikipedia: Defence in depth.

Resources

See Also