Part of the reason why Node.js is so appealing is that it allows for easy application extensibility; you focus on your core competencies, and if you need additional features or functionality, you can include them by adding dependencies.
There are multiple downsides to the modularity of Node.js and the use of external dependencies, but with careful consideration, you can minimize the downsides from an application security perspective.
Many of the packages available to you in the npm registry are safe to use, but it goes without saying that this is not 100% true — dependencies that are safe today may not be safe tomorrow. Furthermore, dependencies that are created and maintained by a single author can be problematic, and dependencies that further rely on dependencies can result in what’s called the Node Module Hole.
In this article, we’ll take a look at what you need to keep in mind from an application security perspective when choosing and managing your npm dependencies, as well as tips and tricks you can employ to make this process easier and more manageable.
Choose your dependencies carefully
When choosing your dependency, take some time to make sure that the package isn’t suspicious or problematic. The npm repository offers package rating metrics and other social cues, such as ratings and popularity, that can signify whether a package is good or not.
There are other cues, too. What’s the maintenance history of the package? How many releases have there been? Has the creator maintained a regular schedule of fixes and upgrades, or has it been a while since anyone has done work on the package?
You should also be on the lookout for changes in ownership over the package; many a time, a creator has handed over the reins to a package, and the new owner(s) introduce malicious code into a once-trusted package.
Know what you’ve used (and what your dependencies use)
The tip of the iceberg is knowing which dependencies you’ve used (and hopefully why), but the modular nature of Node.js means that your dependencies are most likely relying on dependencies, too.
It’s easy to keep tabs on the dependencies you’ve opted for, but it’s important that you keep tabs on the dependencies on which your dependencies rely.
Be as specific as possible
As you know, installing a dependency without including version information results in npm installing the latest version and setting the accompanying line in your app’s package.json file as dependency^x.y.z. If you do this, you’ll get auto-updates in the future to the latest minor version within the scope of the major version specified in package.json whenever you run npm update or do a clean install.
On one hand, making the range of acceptable versions large means that you’ll be more likely to get the latest and greatest (including bug fixes and security features). On the other hand, narrowing the versions that are okay means that your app will be safer. If at all possible, try to avoid being too broad in your version choices; narrow the range of acceptable versions, and lock them in.
Update at regular intervals
The frequency with which you update your dependencies will vary based on your use case, but you’ll want to strike a balance between update too frequently, reducing the likelihood that you’re working with mature (and possibly safer dependencies), and updating too infrequently, causing you to miss out on important changes.
That said, before updating your dependency, we recommend doing some homework to see if there are any issues with the version to which you’re updating. If your application utilizes a lot of dependencies, this can be a tedious task — but you don’t want to be caught flat-footed when it comes to security. One tool that can help with this process is npm-audit, which scans your app for any vulnerabilities due to dependencies that you’re using.
Look for (and consider) alternatives, including micro-dependencies
When you’re looking to fulfill a need using a dependency, your search will likely yield multiple options. Which one should you pick?
Instead of choosing one of the first results or closing your eyes and blindly choosing one, consider using web tools that gather the information you can then use to compare one dependency against another. For example, npm trends can provide you with information about adoption and usage over time.
Furthermore, think about how much of a given dependency will be serving the needs of your app. In a lot of cases, a full dependency would be too much, and the functionality you need can be had elsewhere (in some cases, a micro-dependency would be more than sufficient). For more concrete information, one tool that allows you to see what the cost of adding a specific package is BundlePhobia.
Ask yourself if you really need the dependency
It can be tempting to go straight to the npm registry whenever you need to add functionality to your app, but there’s a lot that is built-in; if you can implement something “natively,” doing so will reduce your overhead, both in terms of adding the dependency and in maintaining said dependency.
When it comes to Node.js development, it can be tempting to take the kitchen sink approach when it comes to the use of dependencies. But, a lack of careful thought today on what should be used, as well as lack of maintenance, can come back to haunt you in the future.
Tips for Managing npm Dependencies was originally published in ShiftLeft Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.
*** This is a Security Bloggers Network syndicated blog from ShiftLeft Blog – Medium authored by Katie Horne. Read the original post at: https://blog.shiftleft.io/tips-for-managing-npm-dependencies-599fc978f9c2?source=rss—-86a4f941c7da—4