headshot of Chris Tonkinson
Chris Tonkinson

tech {enthusiast, practitioner, leader, podcaster, mentor, entrepreneur}

HomeAboutTags



Refactored Podcast

I co-host Refactored, a casual, ongoing conversation between two technology leaders trying to suck a little less every day.

Career Schema Project

I founded the Career Schema Project with the mission of developing open standards and technology to reduce the hassle of online jobseeking.


RSS Subscribe

© 2021 Chris Tonkinson

Subresource Integrity Is Finally Mainstream... Almost


Subresource Integrity (SRI) has finally made its way into the Firefox release pipeline, having already seen release in Chromium/Chrome (currently version 45) and Opera (version 32).

Firefox Developer Edition (the “aurora” channel, currently v43) already includes SRI so the stable branch should see SRI land mid-December, based on the release schedule.

Here’s the CliffsNotes as a refresher on what SRI looks like:

<script src="https://example.com/my/script.js"
        integrity="ALGO-BASE64HASH"
        crossorigin="anonymous"
/>

Where ALGO will be an acceptable hashing algorithm - SHA256, SHA384, or SHA512 (and perhaps others, which would be implementation dependent) and BASE64HASH is the binary digest of the file contents encoded with Base64. How do you get a Base64 encoded binary digest? The W3C working draft on Subresource Integrity recommends using openssl directly:

echo -n "alert('Hello, world.');" | openssl dgst -sha384 -binary | openssl enc -base64 -A

in the real world (where you’re not echoing trivialized code) you could use cat. In addition to that, I’m biased towards longer, slower hashes, so I prefer SHA512.


A passing example

If you check the source of this article, you’ll see a <script> tag directly following this paragraph. It references /assets/examples/integrity-test-pass.js with a correct SHA512 hash in the integrity attribute. If you check your debug console (F12 in at least Firefox and Chromium) you should see your browser has loaded this file as usual. The contents of /assets/examples/integrity-test-pass.js is a noop:

(function(){
  // a test case for valid SRI
})();

The SHA512 hash of the file is qjMqRT1reFX0klfqaBYdVPOR2rg/6+Odk9LQojGKMWD1Sn3TIfnqZ2/z52o04ue6RavKXNLticjX1ZLrHOyGPw==.


A failing example

Directly following this paragraph, you’ll find another <script> tag, this time referencing /assets/examples/integrity-test-fail.js with an incorrect SHA512 integrity value. If you check your debug console, you SHOULD see an error regarding the failed verification, and the script SHOULD NOT have executed. If it did execute, you will see a notice (created by that script) at the bottom of this article.

window.onload = function() {
  $("<div>")
    .prop("id", "sri-failure")
    .addClass("sri-test jumbotron")
    .append($("<h1>")
      .append("If you are reading this, your browser does not yet support Subresource Integrity.")
      .append("<hr/>")
      .append("Check back here the next time your browser updates to see if it's been enabled.")
    )
    .appendTo("#sri-warning");
};

The correct SHA512 digest of that file is wAavEEuwLqE67bOw3hY13q85nLMuOWuAaTUNIxSUsPPN15VzbdpuOlJ98hMfLrd9KAqBR4+9GQJHOdHhpmeZNQ== but I have it entered in the integrity attribute incorrectly as wlHqLoqGTkupQHAygefwRS03a4tyiPKs0KLHRmVikp/I5qCyCn16Fmd/JJd7MeCCIHRwQrOloY335+qW2Cy8ug== (which I got by curling the Google homepage). Just for the sake of it, I’ve also included a CSS file (with correct SRI information) to style the warning and make it as obnoxious as possible.