If you are reading this post, either you, your team or company is probably using open source npm packages in your web applications. Are you aware of any issues and in control of your dependencies?
There are almost 1.5 million packages available in the
public npm registry and up to 90% of the code in modern applications is open source code developed by others.
So what does this actually tell us, besides the fact that we love having the opportunity to just pick what we need, install it and move on?
In short, nowadays dependency management, security and license compliance are much more of an issue which needs to be in focus to avoid the pitfalls of the npm ecosystem.
This post contains a PDF checklist and further down, a bit more information about each of the top 10 best practices.
Enjoy the read!
TL;DR
There are many ways to secure your code supply chain. We at Bytesafe have compiled a PDF with the top 10 security best practices that we think all developers and companies should think about.
Download to check if you are on the right track! 😄
Download a free checklist for npm security best practices (PDF)
The PDF is free to share/repost - Just click on the image to download from the original post.
1. Use a private registry
Using a private registry adds a central hub for all your packages. A layer where you are in control and aware of the packages your team is using. Configure according to your corporate policies and add security policies to only allow approved packages.
Using a private registry also allows for caching of packages (like a transparent npm proxy). Instead of depending directly on the public npmjs.org registry and opening up for security issues. Many developers do not use 2-factor authentication and accounts get hacked all the time due to insecure passwords.
Do you have strict security requirements? Not a problem, just setup a curated firewall registry where every package version has been approved by your security team. Connect team members directly or indirectly to the registry for complete control of the packages available. You might also need to adapt your workflow to balance flexibility (=faster) vs security requirements (=slower).
If you're interested in watching a video how to work with secure private registries, check out this post:
How to use secure private npm registries
Daniel Parmenvik ・ Jun 10 '21
2. Continuously scan for security issues
The npm team has made great efforts to improve security together with the community as a whole.
New malicious packages are continuously detected and added to our advisory database.
The challenge is that there often is a delay between news of new threats and until teams have become aware of the problem. The delay is even greater until the security issues have been resolved by removing, updating or patching the affected packages or versions.
That is why you should make sure that all the packages AND their dependencies are continuously scanned for security issues and enable automatic alerts of new issues. Don’t just rely on triggered scans (like npm audit
) during installation.
More info on how to scan for security issues.
3. Check and be compliant with licenses
Using a package with the wrong license could have catastrophic consequences. License information can be stored in any file of a package, not only package.json
, so don't think of licenses as an afterthought!
- Use tools like Bytesafe to identify license information in all files
- Packages can have multiple licenses. In theory any piece of code can have its own license
- Unlicensed packages are also a problem. How are you to make sure that you are allowed to use the package?
- Restrict problematic or unlicensed packages
- Scan all package files for problematic licenses. Get notified when license issues are identified
More info on how to scan for license issues.
4. Enable a dependency firewall to block packages
Being notified is very important, but most of the time it’s even better to block the bad packages at the door.
Our recommendation is to set up a code supply chain that restricts packages from being added to your private registries
if they have not been scanned, are insecure or contain specific restrictive licenses.
More information on how to use policies to block packages.
Want to get started right away with Bytesafe?
Visit the Bytesafe Getting Started Guide and you will be up and running in less than a minute.
5. Shift responsibility to teams
Even when you use a private registry you should always make intentional changes when you add new packages to a project.
The more packages you use, the greater the risk that one of those packages contain a security vulnerability.
Keeping all those packages up to date and secure only gets worse the larger your dependency list grows.
Making sane choices on dependencies also shouldn’t be the responsibility of single individuals, instead the whole team should take responsibility and discuss the approach to use.
Tools like Bytesafe, that cache and visualize dependencies for all its users, can be used to democratize this information and make it available to all team members.
6. Do not run scripts by default when installing packages
When installing packages there are often scripts executed as part of the installation process. The feature is convenient and useful,
but executing random scripts is also a major risk. Make sure you know what is executed when installing packages.
If you are in a rush and have not checked the scripts, you are much more likely to be safe installing with the --ignore-scripts
attribute.
npm install PACKAGE@VERSION --ignore-scripts
7. Avoid typosquatting risks
Having the belief that you are installing an official package will not help if you're instead installing a malicious package.
There are numerous examples where bad actors have published packages with similar names to official packages.
The intent is to piggyback on the communal trust for popular packages and to include their malicious code instead. Often the affected packages work just like the real ones, to avoid detection for longer. Example includes twilio-npm mimicking the real package name twilio.
Make sure you double check what you install. Don’t automatically accept install instructions as a trusted truth. Review before you run!
More information about typosquatting.
8. Keep tokens and credentials secure
If you are publishing packages to a public repository, it's a good idea to centralize the token management. Store the maintainer token and publish with Bytesafe. Avoid the risk and hassle of distributing the token to all developers.
Avoid accidental exposure of sensitive credentials. Even though npm has added features to detect secrets, make it a habit to update your ignore files (e.g. .npmignore, .gitignore etc).
9. Use the exact same package versions in your different environments
Getting consistent and deterministic results across different environments is an ongoing issue for any dev team.
Unless the correct commands are run, or the state of project files are perfectly in sync, it is very easy to get a slightly different set of package versions installed as your node_modules
. Even though you were trying to replicate another person's environment.
The issue is even more tricky if you have multiple dev teams and different environments (Dev, QA/Test, Prod) that all want to be able to replicate a specific state.
And most critical, you always want your production CI/CD pipeline to build with the exact same package versions you developed and tested with.
To succeed, your teams should be skilled in the use of lock files (package-lock, yarn-lock, shrinkwrap etc.), keep them up to date and committed to the team's repository.
Additionally, any user that only wants to replicate a specific state should make use of the npm clean install command, npm ci
.
This will try to install the exact versions to replicate a specific state of node_modules
. In most cases this works, but does not cover transitive dependencies (dependencies of dependencies).
Any easier solution? For teams that require fully deterministic results Bytesafe offers the Freeze policy ❄️. The freeze policy makes a whole registry read-only allowing for fully consistent results.
You are able to snapshot exactly what versions were used and use that snapshot regardless of environment. As ALL dependencies are frozen, this also includes transitive dependencies that are reproduced exactly.
10. Make sure the whole team uses the private registry
Your team’s code supply chain is only as strong as its weakest link. Ensure all packages flow through the private registry and
change the direct dependency to npmjs to an indirect one instead.
Connect additional package sources to Bytesafe (git repositories or other private/public registries) to get a true central hub for all packages.
npm config set registry 'https://example.bytesafe.dev/r/default/'
What are your thoughts on npm security best practices?
What best practices do you use? Feel free to comment if you agree 👍, disagree 👎 with something in this post, or if you think something is missing ❗.
For the latest updates on Bytesafe, follow us on Twitter (@bytesafedev).
Sign up for Bytesafe
Signing up for Bytesafe is free for individual developers and the 30-day Teams trial is free too.
Top comments (0)