Adding Sub Resource Integrity (SRI) checksums with Gulp

As I mentioned when I recently wrote about upgrading to Gulp 4, I had a number of posts in draft mode relating to my new development process with Git and Gulp.  This post is going to be a combination of two of those.

Let me start by saying the Sub Resource Integrity (or SRI) is excellent, and you should absolutely be using it.  Some of the notable data breaches in recent months (and boy have there been some big ones!) have been due to supply chain attacks.  This is where a third party library has been included on a website, but then an evil doer has managed to modify that file, and it is therefore pulled into the website, which could be your website, without your knowledge.  This answer to this is SRI.

Now for externally hosted third party libraries, such as jQuery, you can manually add the relevant attributes.  It would look something a bit like this…

<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>

The attributes included are…

  • src – the location of the file on an external server
  • integrity – the hash (which can be SHA256, SHA384 or SHA512)
  • crossorigin – needs to be set depending on the external server configuration

The browser will download the file as normal, but before executing any of the code, it checks to ensure that the has of the contents of the file matches the hash listed in the “integrity” attribute.  If it doesn’t match, it won’t run the code, keeping your website safe and secure.

If you have locally hosted files, they’re a lot less likely to suffer from an unauthorised change, in the sense that if they can get onto your server to edit the javascript files, they can problem get access to your page source as well, in order to remove the SRI checks.

Having said that, there is still the matter of a man-in-the-middle (or MITM) attack.  In this case, part of the network infrastructure (could be your ISP’s server, or the urouter you’re connecting to) has code that intercepts files and modifies them – there have been a number of examples of this, including airlines adding things into pages if you’re on the airplane or airport wifi.

In order to guard against this, we can automatically calculate the SRI hashes for local files as part of our Gulp workflow.

Originally I did this using the gulp-sri-hash plugin, but I found that it struggled with PHP files.  For this reason, and the fact that you can only have one hash per file, I decided to write my own – enter gulp-sri-php.

To start, we need to install it…

npm install --save-dev gulp-sri-php

…and then we need to include it…

var srihash = require("gulp-sri-php");

 

…and finally we can add it to our “index” task…

var index = function() {
  return gulp.src("build/index.php")
    .pipe(srihash({"algorithm":"sha384"}))
    .pipe(gulp.dest("build"));
};

This is now processing our “index.php” file in order to find javascript and stylesheet links which are local (relative path), which don’t already have the “integrity” attribute, and then calculating the value and adding it into the HTML tag.

For example, this…

<link rel="stylesheet" href="css/style.css">
<script src="js/script.js"></script>

…becomes…

<link rel="stylesheet" href="css/style.css" integrity="sha384-54Zl+ll6X3PdHPKfBjEU8TtSZc29x/y3anYm06KOlBpMAZcRS9Zw4YwloXptTN0n" crossorigin="anonymous">
<script src="js/script.js" integrity="sha384-1hPB2dkVqfc4TsrWjuj7Ot6EjZpPCT8SXkMPcFVS72GywaLYlgGGC21Bden2FYc0" crossorigin="anonymous"></script>

The default is to calculate the SHA256, SHA384 and SHA512 hashes, meaning that as long as long of them matches the file will be used. However, I find just generating the SHA384 usually does the trick.

These files are now protected from any manipulation that may occur “on the wire”, as their contents must match these calculated values before they are executed.