Iain Lumsden

Keeping up with the dependencies

This will not be the last time I write about dependencies, the software libraries on which our software depends. Writing secure software is not just about the code you write, it also includes all the code on which your code has a dependency. For this reason it is the source of security problems, which extend from errors in this code, all the way to this code acting maliciously. I will cover these area in other posts. This post is dealing with the most fundamental of securing your dependencies, which is keeping your dependencies up to date, and why this necessitates that you keep the number of libraries that your software depends on as small as possible.

When you start a new project all your dependencies will probably be on the latest version, if not take a good long look in the mirror and ask yourself if your really want to maintain this software if you have a maintenance task which is too hard to overcome as soon as you have started. You then write your code, which is minimal because of your good choice of libraries, it meets the business requirements, and is shipped to production. This is a perfectly normal software development story. Now because this software continues to work you are moved onto a different project/feature and the working software is ignored. This is where the problem starts.

The main problem I have had with this approach is when after a year a security vulnerability is found in your software . If you're lucky your will be the same person who wrote this in the first place, in all likelihood you are not. Through your analysis you find that this was introduced by one of the libraries you depend on. You find the new version which fixes this problem (if you are lucky) update the version, and everything is even more broken than before you started. The libraries API changed between versions and you now need to update the code to accommodate this. You diligently follow the upgrade steps, run the app, and it is still broken. This time it turns out another library you use requires the older version of the library you just updated, you go off and update that version to a compatible one, and repeat until the software works. This is the best case scenario where an upgrade path was available and the libraries you had used fixed the problems you encountered. In the worst case you probably need to rewrite.

This was just an example of software maintenance, it can be frustrating, but it is part of the job of a software developer. The problem was that it was deferred until something catastrophic went wrong and it stopped working. The upgrade had to be done at the worst possible moment with the leap in dependency versions as large as it could possibly be. The fundamental problem was not that maintenance was taking place, it was that insecure software was running while all of the deferred maintenance was caught up on.

The was to make this kind of crisis less dramatic is to check for new versions of dependencies regularly, maybe every month. Upgrade whenever you find a new version. The changes shouldn’t be too dramatic if it is happening regularly, even if they are , there is no rush, as the is no crisis. You have time to make a well argued business case to take the upgrade steps. This continuous Why will means that where software stops working, or a vulnerability is found the fix is only the fix. This will make fixing problems seem easier as it is not combined with deferred maintenance.

We all make mistakes in our code, even the people who write the libraries make mistakes or cut corners to get things released. These mistakes and omissions are corrected by newer versions, by keeping up to date with the latest versions you are also included the quality of your code base, while also allowing you to benefit from new feature that can be added. New versions are not released to spite your, they are there to help you, it is up to your to accept this help.

This is where the number of libraries you depend on becomes important. If it is five, it is really no trouble at all, if it is twenty it will start to become onerous, if it is fifty it probably be overwhelming. Remember this when when designing projects, we are just designing the tip of the code iceberg, make sure that the dependencies that sit below the water out of sight won’t cause you problems later on. Each additional dependency is something that can break and may cause problems with dependencies you already have. Another good practice is when checking your dependency versions also identifying what can be removed, keeping your dependency set to the minimum that is required for your software to function will reduce your maintenance burdan, and will help you keep your software secure.

In summary the way to stay away from upgrade hell is to reduce the number dependencies to the absolute minimum. Do not defer maintenance, keep on top of your dependency versions, you will have to do it at some point, and it is best that it happens when your company and customers are not at risk. Finally audit which dependencies you actually need, each one removed is less work for you.

I will be staying on the topic of dependencies for my next few posts, look out for more posts on dependencies and increased attack surface, auditing and your responsibility when using someone else's code, and options with unmaintained libraries.