Analysis of CSP in the Alexa Top 1M sites (April 2016)

I recently wrote about the state of security in the Alexa Top 1M sites, particularly the depressingly low utilization of the many security headers available to site developers. Today, I'm talking about Content Security Policy (CSP).

By whitelisting specific sources of content and by disabling the use of inline JavaScript, CSP can nearly eliminate the class of attacks known as cross-site scripting (XSS) attacks. So how common is its usage amongst the Internet's most popular websites? Let's take a look:

Result Count Percentage
CSP implemented without using 'unsafe-inline' or 'unsafe-eval' 45 .0047%
CSP implemented the same as above, but with default-src 'none' 8 .0008%
CSP header allows style-src 'unsafe-inline' 61 .0064%
CSP header allows script-src 'unsafe-eval' 68 .0071%
CSP header uses http: source on an https site 15 .0016%
CSP header invalid 27 .0028%
CSP header allows script-src 'unsafe-inline' 3392 .3540%
No CSP header 954791 99.62%
Total number of successfully completed scans 958407  

Yes, that's correct: only about .37% of the top million sites use CSP at all, and of that tiny percentage, only 3.3% (.012% overall) have strong CSP policies that block the use of inline JavaScript. For a specification that has had wide browser support for over two years, that's almost embarrassingly low. I'm not sure if it's because the CSP specification is too complicated to understand or too complicated to implement, but web security professionals are failing here.

Of that meager .37%, what CSP directives are seeing use?

Directive Count Percentage
script-src 2500 69.66%
style-src 2016 56.17%
default-src 1913 53.30%
img-src 1555 43.33%
frame-src 1344 37.45%
font-src 1317 36.70%
connect-src 1203 33.52%
report-uri 1037 28.89%
object-src 980 27.31%
frame-ancestors 916 25.52%
media-src 912 25.41%
child-src 126 3.51%
form-action 70 1.95%
reflected-xss 39 1.09%
referrer 33 0.92%
base-uri 22 0.61%
sandbox 15 0.42%
plugin-types 4 0.11%
manifest-src 1 0.03%
block-all-mixed-content 0 0.00%
upgrade-insecure-requests 0 0.00%

It's interesting to note how common frame-src, referrer, and reflected-xss are, considering they have been deprecated since CSP1. I myself struggled with removing frame-src, simply because child-src is not yet supported everywhere.

Although the HTTP Observatory doesn't currently try to catch errors in CSP policies, they are quite common. In my investigations, I discovered that over 3% of CSP policies contained errors. Here are some of the more common errors I discovered:

Content-Security-Policy: *
Content-Security-Policy: 'self'
Content-Security-Policy: allow https://example.com ...
Content-Security-Policy: "default-src https://example.com ..."

I have no idea how the browsers interpret these errors, but it's almost certainly not what the site operator intended. Whoops! The upcoming version of the HTTP Observatory should report on these types of errors so that site operators can be certain that browsers aren't misinterpreting their intentions.

[Category: Security] [Permalink]


Analysis of the Alexa Top 1M sites (April 2016)

One of unsung heroes out there when it comes to advancing the overall security of the Internet is Scott Helme. In addition to report-uri.io (a CSP/HPKP violation reporting service), he runs securityheaders.io, a site that helps show you if you're utilizing the many available options when it comes to securing your web site.

It was the latter that inspired the creation of the Mozilla HTTP Observatory, a public service that goes a bit deeper and tells you not just whether you are using these headers, but if you're using them correctly and securely.

Having recently gotten the HTTP Observatory to a usable state, I decided to scan the Alexa Top 1M sites to see how well that engineers and developers on the biggest sites on the Internet are doing. As Scott found out, the results are pretty dismal. I'll be doing more detailed posts on each of these sections as I find the time, but even the basic statistics are depressing.

Content Security Policy (CSP) .005%1 / .012%2
Cookies3 1.88%
Cross-origin Resource Sharing (CORS)4 93.78%
HTTPS 29.64%
HTTP → HTTPS Redirection 5.06%5 / 8.91%6
Public Key Pinning (HPKP) 0.43%
  — HPKP Preloaded7 .414%
Strict Transport Security (HSTS)8 1.75%
  — HSTS Preloaded7 .158%
Subresource Integrity (SRI) 0.015%9
X-Content-Type-Options (XCTO) 6.19%
X-Frame-Options (XFO)10 6.83%
X-XSS-Protection (XXSSP)11 5.03%

Because these tests are a lot more strict than on securityheaders.io, the overall grade distribution is much lower:

Grade HTTP Observatory securityheaders.io
A+ .003% .020%
A .006% .072%
B .202% 2.38%
C .321% .029%
D .999% 3.16%
E .870% 6.10%
F 97.60% 88.20%

And just who are the .003% that managed to land an A+ grade with a score of 100 or greater on the HTTP Observatory?

Notes:

  1. Allows 'unsafe-inline' in neither script-src nor style-src
  2. Allows 'unsafe-inline' in style-src only
  3. Amongst sites that set cookies
  4. Disallows foreign origins from reading the domain's contents within user's context
  5. Redirects from HTTP to HTTPS on the same domain, which allows HSTS to be set
  6. Redirects from HTTP to HTTPS, regardless of the final domain
  7. As listed in the Chromium preload list
  8. max-age set to at least six months
  9. Percentage is of sites that load scripts from a foreign origin
  10. CSP frame-ancestors directive is allowed in lieu of an XFO header
  11. Strong CSP policy forbidding 'unsafe-inline' is allowed in lieu of an XXSSP header

If you're in a hurry and want to start digging into my data before I can, feel free to grab the data dump and have at it.

[Category: Security] [Permalink]


SVG + CSP: An Unappetizing Alphabet Soup

When I decided to rewrite my personal website, I thought to myself, “Hey, April! You're a security professional who focuses on web security. It would be practically embarrassing if you didn't implement Content Security Policy to demonstrate your competence.”

I simply followed my usual procedure: start with default-src 'none', and keep adding sources until all the console errors go away. That lead me to the following CSP header:

Content-Security-Policy:
    default-src 'none';
    child-src https://www.youtube.com;
    font-src 'self' https://fonts.gstatic.com;
    frame-ancestors 'none';
    frame-src https://www.youtube.com;
    img-src 'self';
    media-src 'self';
    script-src 'self';
    style-src 'self' https://fonts.googleapis.com

I walked away blissfully, knowing that some ne'er-do-well whould be thwarted in their attempts to find any XSS vulnerabilities in my pointless, mostly static personal blog. That is, until I clicked Contact and gasped in horror…

At first, I thought that I had made a mistake with my SVG files, but opening them up directly rendered them in full color. And there was nothing at all in the console log about them, either. After a pile of fruitless Google searches, a tip by my good friend Chuck Harmston led me to consider my CSP policy.

See, SVG files are not just a pile of binary data like most raster images. They're vectors, created mathematically, and defined via XML. The GitHub icon's content looks like this:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 256 250" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
    <path d="..." style="fill:rgb(246,188,246);fill-rule:nonzero;"/>
</svg>

Firefox was considering style="fill:rgb(246,188,246)" to be an 'unsafe-inline' style, and therefore blocking it. But it considers it to be an 'unsafe-inline' style inside the SVG's context, hence the lack of console errors. I didn't want to add 'unsafe-inline' to 'style-src' for my entire site, so I ended up creating a completely different CSP directive just for SVGs:

server {
    add_header Content-Security-Policy "default-src 'none'; child-src https://www.youtube.com; font-src 'self' https://fonts.gstatic.com; frame-ancestors 'none'; frame-src https://www.youtube.com; img-src 'self'; media-src 'self'; script-src 'self'; style-src 'self' https://fonts.googleapis.com";

    location ~ \.svg$ {
        add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; style-src 'self' 'unsafe-inline'";
    }
}

The nice thing about this policy is that it has the added bonus of disabling all script execution inside SVG files, itself a huge security risk. In any case, I thought this madness was crazy enough (and undocumented enough) that I opened up a bug for it.

[Category: Standards] [Permalink]


Creating Ascending Ringtones for iOS / iPhone

When my most recent phone got abandoned by T-Mobile, — leaving me with a pile of security vulnerabilities — I finally give up. Despite really enjoying the Android user interface (particularly with Nova Launcher), I just couldn't stomach buying Yet Another Android Phone™ just to have the latest version. So now I'm the proud owner of an iPhone SE, which is delightfully hand-sized.

On Android, the process of installing a ringtone goes roughly as follows:

  1. Plug in your phone
  2. Drag your audio files (midi, mp3, m4a, etc.) to the proper folder

I had assumed it couldn't possibly be that much more difficult on the iPhone. But getting custom ringtones onto an iPhone is a giant pain in the ass. Guides on the internet go roughly as follows:

  1. Open the Kafkaesque nightmare that is iTunes
  2. Drag your audio file into iTunes
  3. Go into Get Info for the song
  4. Set a start and stop time with a max duration of 30 seconds, because of pointless technical limitations
  5. Right-click on the song and create an AAC version
  6. Show in Finder, finding the file on your local filesystem
  7. Drag that file to your desktop
  8. Rename its extension from .m4a to .mpr
  9. Delete the AAC file from iTunes
  10. Drag the .m4r file into the Tones section of iTunes
  11. Plug in your phone, go to the Tones section, and select the new ringtone
  12. Sync it

Of course, this doesn't get you an ascending ringtone, one of my favorite Android features. So I turned to ffmpeg, one of most byzantine command line applications ever created.

$ ffmpeg -i "Android Ringtone.mp3" -ss 00:00 -t 00:30 -af "afade=t=in:ss=0:d=10" -f mp4 "iOS Ringtone.m4r"
ffmpeg version 3.0 Copyright (c) 2000-2016 the FFmpeg developers
  built with Apple LLVM version 7.0.2 (clang-700.1.81)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/3.0 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-opencl --enable-libx264 --enable-libmp3lame --enable-libxvid --enable-vda
  libavutil      55. 17.103 / 55. 17.103
  libavcodec     57. 24.102 / 57. 24.102
  libavformat    57. 25.100 / 57. 25.100
  libavdevice    57.  0.101 / 57.  0.101
  libavfilter     6. 31.100 /  6. 31.100
  libavresample   3.  0.  0 /  3.  0.  0
  libswscale      4.  0.100 /  4.  0.100
  libswresample   2.  0.101 /  2.  0.101
  libpostproc    54.  0.100 / 54.  0.100
[mp3 @ 0x7fee0b80a800] Skipping 0 bytes of junk at 10809.
Input #0, mp3, from 'Android Ringtone.mp3':
  Metadata:
    title           : Oh Yeah That Song
    artist          : That One Gal or Guy
    album           : That Album You Keep Buying Again and Again
    TT1             : Some Dumb Organizational Tag
    track           : Insert Integer Here
    genre           : Probably my Favorite Genre
    date            : Another Integer that Represents a Good Year in Music
  Duration: 00:02:01.55, start: 0.011995, bitrate: 167 kb/s
    Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16p, 166 kb/s
Output #0, mp4, to 'iOS Ringtone.m4r':
  Metadata:
    title           : Oh Yeah That Song
    artist          : That One Gal or Guy
    album           : That Album You Keep Buying Again and Again
    TT1             : Some Dumb Organizational Tag
    track           : Insert Integer Here
    genre           : Probably my Favorite Genre
    date            : Another Integer that Represents a Good Year in Music
    encoder         : Lavf57.25.100
    Stream #0:0: Audio: aac (LC) ([64][0][0][0] / 0x0040), 44100 Hz, stereo, fltp, 160 kb/s
    Metadata:
      encoder         : Lavc57.24.102 aac
Stream mapping:
  Stream #0:0 -> #0:0 (mp3 (native) -> aac (native))
Press [q] to stop, [?] for help
size=     620kB time=00:00:30.00 bitrate= 169.2kbits/s speed=  21x
video:0kB audio:614kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.976624%
[aac @ 0x7fee0b819400] Qavg: 1646.151

Here are what the switches mean:

  • -i "Android Ringtone.mp3" the input file
  • -ss 00:00 the start time (at the beginning, in this case)
  • -t 00:30 how long of a segment (30 seconds)
  • -af "afade=t=in:ss=0:d=10" starting at 0 seconds in, fade in over a duration of 10 seconds
  • -f mp4 treat it as mp4 audio, since ffmpeg doesn't recognize the .m4r extension
  • "iOS Ringtone.m4r" the output file

Just drag that file into iTunes, sync, and it's done:

[Category: Personal] [Permalink]