The adoption of agile practices has resulted in the emergence of shift-lift testing, where testing is performed much earlier in the Software Development LifeCycle (SDLC). Traditional waterfall models performed testing to the right of, or following, development. The benefits of testing earlier and more often cannot be underestimated. However, where does this leave security and security testing.
DevOps devotees will no doubt be familiar with these concepts and how security should be shifted as far left as possible. The very term DevSecOps is even contentious, with some arguing and coining the term SecDevOps to highlight just how far left security should be considered. So how do companies integrate and enhance security within their SDLC and in particular, how are they dealing with dependencies?
As with most things there are some issues to recognize, which will need to be accepted and some challenges that must be overcome.
The first step is identifying just how far left security should be considered. In an ideal world this should be done very early on in the design and planning phases, where security considerations and risks are identified, added to the requirements and then appropriate measures are taken to address them. The reality is that this, whilst important, only goes a small way to protecting your application. The first operational, tangible difficulty arises with the code itself, often well into the development lifecycle.
It may come as a surprise to some that modern applications contain (on average) less than 20% custom code. The majority of the code comes from frameworks and third-party libraries. As pressure on developers mount to create applications faster than ever, reliance on open-source code has increased exponentially. These libraries are often available within an assortment of package managers e.g. NPM, dotnet, PIP, or Composer. As a result, these dependencies often appear in 1000s of projects, therefore security testing is often performed at scale by hundreds, if not thousands, of individuals, however the potential impact and value of successful exploitation is magnified. Hence, the need to manage your supply chain security and prevent the addition of vulnerable packages into your SDLC. The good news is that it is a relatively simple process to incorporate and can lead to substantial improvements in your security posture.
How to check for vulnerable dependencies
Depending on your platform and package manager, there are a number of freely available tools that can be used to identify vulnerable packages and their dependencies. Whilst these solutions may not be as comprehensive or provide as much coverage as commercial or professional solutions, it’s a great start for any independent developer, start-up, or small team.
NPM
Running NPM’s audit command will list vulnerable dependencies in your project and can optionally try to fix these with the -fix flag added. npm-audit is triggered by default with every npm-install:
npm-audit
dotnet
Using the dotnet CLI you can check for any known vulnerabilities in dependencies using:
dotnet list package --vulnerable
Composer
Roave/security-advisories is a composer meta-package that contains a composer JSON file. Adding to the require-dev section in a project’s composer JSON file will cause a conflict with any known vulnerable packages and refuse to install them:
composer require --dev roave/security-advisories:dev-latest
While True: Automate
Of course, running these tools is a manual process that doesn’t fit with modern DevOps/DevSecOps practices. The first thing to do is to automate the detection of vulnerable packages and prevent them from entering your source control. You can add the commands described above as part of your pipeline, which may be a good starting point. There is an entire market designed around the sale of Software Composition Analysis (SCA) tools. These tools typically identify open-source components, their license compliance, and security vulnerabilities. Some can even help with fixing issues identified.
GitHub has added its Dependabot feature to monitor for vulnerable dependencies, when it detects them it can raise a pull request to update the manifest to the latest version. Gitlab also has a dependency scanning feature. It is worth noting that these features are limited to paid tiers or self-hosted plans.
Bitbuckets’ offering is an integration of Snyk’s tool (which will integrate into Gitlab and GitHub as well). This is also a paid offering though there is a free tier level that includes a limited number of tests.
There are also a variety of other third-party vendors that are vying for a place in your pipeline, such as Deps – a CLI tool, that integrates with most CI Tools to create pull requests. This is great if you want a custom solution.
The first step is always detection of these vulnerable packages. The next step is notification, this as we’ve seen is often done by means of pull requests. These can then be reviewed either by your security team or developers who can prioritise and triage these issues. You will want to decide on the criteria for this, often this focuses on the severity of the vulnerability as measured by its CVSSv3 score. There are times when the dependency itself may be vulnerable but is not used in a vulnerable way or additional measures exist that nullify the vulnerability. Some updates may break functionality, some dependencies have vulnerable sub dependencies that often you won’t be updating yourself. So, it is important to have a process in place to identify, assess and triage vulnerable dependencies within your software development process.
Once risks are prioritised you can then explore the remediation. This may at times involve code changes, other times it may not, and the packages can be updated as required. Many of the tools available allow you to auto update, and some allow you to set custom criteria for this e.g., update to minor versions but not major versions.
Open-source components are now a mainstay of application development, and their usage is only increasing. Implementing a comprehensive supply chain management process as part of your DevOps practices can reduce your risk exposure and minimize the attack surface for malicious actors. The implementation of these practices is straightforward, they don’t require substantial configuration and should be viewed as a first step towards a more secure DevOps posture.