How Do You Keep Your JavaScript Dependencies Up-to-date?

    James Hibbard
    Share

    This is the editorial from our latest JavaScript newsletter, you can subscribe here.

    JavaScript Dependencies — Skull of death

    Recently, security researchers analyzed 133,000 websites for outdated JavaScript libraries. Their findings, presented in a whitepaper, Thou Shalt Not Depend on Me: Analysing the Use of Outdated JavaScript Libraries on the Web, do not make for happy reading. Of the websites analyzed, 37% loaded insecure JavaScript, either directly or via a third-party service, such as advertisers.

    This made me sit up and take notice. The libraries these researchers were checking for were 72 of the most popular open-source projects out there — libraries like Angular and jQuery that we all use every day. I’d never really stopped to think whether an outdated version of jQuery could present a serious security threat. And I had (almost) certainly never gone back to update an old version of jQuery on a website I had made. Was this something I should have been doing?

    My Career as a L33t H4x0r

    So, now I was curious and decided to see if I could use an outdated version of jQuery to hack one of my own pages. I started off searching for “jQuery security vulnerabilities” and pretty soon stumbled across this issue on jQuery’s GitHub repo. People were pointing to this as a potential cross-site scripting vulnerability which meant that an attacker could execute arbitrary code at the request’s origin. That sounded promising …

    The issue was easy enough to reproduce — the problem was that jQuery was executing every text/javascript response it received when performing a $.get() request — but that was as far as my excitement went. As one of the jQuery maintainers pointed out in the thread, this “exploit” was similar to including third party code via <script> tags. This wasn’t likely to bring my website to its knees and was hardly the stuff hacking movies are made of.

    Take 2: A Bit of Session Hijacking

    Not wanting to be deterred, I imagined what I would do if the exploit had worked and I could execute arbitrary code on a user’s computer. One thing we are often warned against is session hijacking where a malicious script can manipulate a user’s cookies to gain unauthorized access to information or services they are logged into. So, I thought I’d try my hand at that.

    I started off by attempting to print out the cookies of a service I was logged into (a simple Rails app which used the Devise gem for authentication). I opened the browser console and entered document.cookie expecting to see my session token returned, which I could ajax off to a remote server for all kinds of nefarious purposes … But unfortunately, this command just returned an empty string. Closer inspection revealed that Devise uses HTTPOnly cookies, that are not accessible via JavaScript to prevent exactly this kind of attack. Curses! Hacking was proving to be considerably harder than I hoped.

    It’s a Jungle out There

    Ok, so it turns out I’m not the world’s best hacker, but joking aside, it is actually a jungle out there! Browser security has come on in leaps and bounds in the past years (HTTPOnly cookies being an example in point), but online criminals are always a step or two ahead. The list of possible attacks is seemingly endless and as you build more complicated applications, the libraries you use will (unwittingly) introduce vulnerabilities into your code base. Keeping these libraries patched to the best of your ability, or at least being aware that some are potentially insecure, has to make sense, right?

    Our original outdated version of jQuery shouldn’t prove too challenging to update, but what about when an application starts to grow? Luckily there are a few tools and services to help you. For example the npm-check package does what it says on the tin and will check for outdated, incorrect, and unused dependencies. It will also kindly provide a link to a package’s documentation so you can decide if you want the update. There are also services such as Greenkeeper.io and Snyk which automate the process, but these are starting to stray into Node territory.

    One for the Road

    There’s one more tip that I’d like to share which goes some way to mitigating the danger posed by third party scripts. This is to verify third-party content using subresource integrity (SRI). You might have come across this if you’ve attempted to include jQuery from the jQuery CDN lately. You’ll see something like:

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

    What’s new here is the integrity attribute on the <script> tag which can be used to specify a base64-encoded cryptographic hash of the resource you’re asking the browser to fetch. This effectively allows the browser to ensure that resources hosted on third-party servers have not been tampered with.

    Using SRI is now a recommended best-practice. You can use the SRI Hash Generator to create hashes of your own.

    Conclusion

    Keeping your application’s JavaScript dependencies up-to-date is just one small piece of a much larger security puzzle. For small projects this is probably doesn’t represent much effort, but as a project begins to grow, so to does the time and effort involved in ensuring that all of the project’s dependencies are adequately patched. I think this is an important topic, but one which receives far too little press — we all tend to fire and forget when it comes to installing JavaScript libraries and modules.

    But what do you think? How much importance do you put on keeping things up-to-date? Would your site be one of the 37% loading insecure JavaScript? How much of a problem is this for our industry as a whole? Let me know in the comments below.