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]



Fifteen Years is a Solid Run

After fifteen years of being on twoevils.org, I've decided that it was time to move to a new domain.

$ whois twoevils.org
Domain     : TWOEVILS.ORG
Domain ID  : D80038331-LROR
Status     : Live
Registered : 2001-11-20
Expiry     : 2017-11-20

When I first registered the domain, I used exclusively lesser@twoevils.org, but nobody ever got the joke. “Who's lesser?” I eventually switched to using april@twoevils.org which made even less sense and still garnered weird looks.

$ whois pokeinthe.io
Domain     : pokeinthe.io
Domain ID  : DOM-388773
Status     : Live
Registered : 2016-03-27
Expiry     : 2017-03-27

Hopefully I (and everybody else) will still find pokeinthe.io just as amusing in 2032.

[Category: Personal] [Permalink]