Node.js: Best practices & the importance of security

Any organization with a substantial technology footprint is using open-source software. While they've long been viewed with some degree of skepticism in the enterprise, open-source solutions are increasingly more accepted, with technology leaders such as Capital One embracing these solutions to supercharge their innovative postures. The collaborative nature of open source results in countless developers with diverse backgrounds contributing to the progress of technology solutions that are free to use. In terms of innovation, this dynamism is difficult to match for any closed-source project.

Yes, We’re Open Source!

Learn more about how we make open source work in our highly regulated industry.

Learn More

Incidentally, Node.js is a shining example of a prosperous open-source project, which demonstrates the sizable impact an open approach can have. Enterprises that value technological innovation put speed, scalability and security above all else. In this regard, Node.js is a robust platform that has revolutionized how enterprises develop and deploy applications.

But integrating open-source solutions in an enterprise environment has its challenges, and Node.js is no exception. While the open-source movement has produced diverse innovations, its philosophy sometimes stands in contrast to real-world business concerns. To address these challenges, Capital One has established a comprehensive governance model that includes policies, procedures and guidelines for open-source software usage. 

More importantly, Capital One invests in engineering talent by providing resources and education, which helps its teams stay well-informed about the use of open-source software. In doing so, the company continues to innovate and build secure, reliable and scalable applications with Node.js while effectively managing risk in an enterprise environment.

An example of an attack on a supply chain

Today, JavaScript is the most widely used programming language in the world — its popularity is due in no small part to its strong open-source community. This community has ushered in an endless array of libraries, frameworks and tools that are free for developers and businesses to use. In turn, a culture of sharing and collaboration has risen within the ecosystem. In short, leveraging JavaScript as a language and a community makes it easier for developers to build reliable and performant applications.

But this ubiquity has a downside. The JavaScript ecosystem is regularly targeted by bad actors. Given its massive growth and popularity, Node.js and the organizations using it are often the focus of hopeful hackers. While Node is highly secure, oversights in development and dependency management can lead to costly attacks. One example is called a supply chain attack, and it's one that enterprises and large organizations are particularly exposed to. 

By default, Node.js uses npm as its package manager, which happens to be the largest software repository in the world. While the two technologies are distinct, they're seldom used as such. Most organizations using Node.js also use npm to manage app dependencies, including those that aren't published to the npm repository. Hackers take advantage of these unpublished packages to infiltrate company networks. 

How npm works with Node.js  

  1. A developer creates an unscoped package to use in an application but doesn't publish it to the npm registry. However, they upload it to a public GitHub repository that anyone can explore.
  2. A hacker scours GitHub in search of unscoped packages, eventually locating the package the developer pushed to the GitHub repository. The hacker verifies the package isn't published to npm, meaning it's most likely an internal company package.
  3. They pull the package down from the repo, add malicious code to it, increment the version and then publish their malware to the npm registry. Then, when developers upgrade their Node.js installations or perform a new install, they deploy the malicious code, and the hacker now has access to the organization's network.

These types of attacks can have serious consequences for enterprises. Rather than avoidance of Node, however, the solution is awareness. The above attack is easily avoidable by scoping Node.js modules to an organization and making code repositories private. Simply put, it's essential to build best practices for security, testing and package management into development processes. 

Reduce risks by being well-managed

While there are risks associated with using Node.js, most of them are mitigated with proper planning and management. Being responsible for an organization’s vulnerability management in terms of how packages are used and upgraded is the most important factor in managing threats. One of the biggest risks of tools such as npm is that developers can instantaneously pull down packages with countless dependencies while having no understanding of what the code in each dependency does. 

1. Be intentional about Node.js version usage  

It is important to take a highly managed approach. The development of metrics and dashboards, for example, allows teams to see at a glance how well-managed they are at any given moment. Meanwhile, having established stages for each Node.js package in use helps in tracking and compliance These stages, for example, could include upstream monitoring, adoption criteria, support lifecycle and end-of-life deprecation policies. An example of a this “maturity criteria” allows an organization to define  acceptance criteria that follows the Node.js Release Working Group pipeline, but tuned for the organization’s risk tolerance, so some  caveats might be:

  • Only LTS versions are considered for production.

  • Minor update releases are delayed for “allowed use”  by 2 weeks.

  • For older versions of node, only Active and Maintenance statuses are considered, with a preference for Active.

  • Security Releases are accepted on the day of release.

Lastly,  is it important that deprecation of versions occur according to the Node.js Working Group schedule, and having a plan to move to a new version before the EOL date. Juggling all these Node.js and dependency versions sounds complicated, but it's actually easily automated with DevOps techniques and tooling. 

2. Make use of "golden images"  

Node.js dependency management is infinitely easier with containerization. In an organization, these are usually  centrally owned. The central tem typically builds and hosts the organization’s  golden images, which are most often Docker containers. These images are the basis for all downstream containers that teams use to base their own release containers on, and they regularly receive any pertinent updates and patches specific to the OS they're using. Likewise, when one moves to a new LTS version of Node.js, all the golden images are updated accordingly. Additionally, these containers can be tuned for a specific enterprise’s usage and compliance.

3. Centers of Excellence that are well-managed  

While best practices help developers be more intentional about Node usage, Capital One has established Centers of Excellence to help manage Node.js and other essential open-source software it uses. Each Center is specific to each approved language in use at Capital One. These Centers of Excellence help drive a culture of responsible use.

Capital One's Node.js and JavaScript Center of Excellence is made up of subject matter experts (SMEs) from all over the company. For fair representation, the Center has at least one member from each major platform using Node.js or JavaScript within the organization. The Center’s primary goal is the governance and recommendation of best practices and policies for using Node.js and JavaScript at Capital One. 

A few of the Center’s many responsibilities include:

  • Approving each LTS Node.js version for production as they're released while adhering to Capital One's maturity criteria

  •  Ensuring any backlogged items related to Node.js or JavaScript policy are moved forward

  •  Using code reviews and developer education to promote the safe and responsible usage of Node.js and other open-source software

  • Identifying and promoting opportunities for developers to contribute to Node.js and other open-source initiatives outside of Capital One

In short, Capital One's Node.js and JavaScript Center of Excellence is responsible for overseeing much of the development and implementation of policies for Node.js usage. The Center also works in conjunction with Capital One's Open Source Program Office (OSPO) to drive responsible usage of open-source JavaScript.

 4. Tracking package usage through SBOMs  

To effectively manage the usage of open-source packages in enterprise environments, it's essential to track package usage and maintain a Software Bill of Materials (SBOM). This is a record of all the packages used in a software release and is a required artifact for any release. The benefits of SBOMs include:

  • Detailed usage lineage that assists in vulnerability detection and identifying affected components

  • The ability to audit software releases, providing visibility into usage, including where and how often each package is used

  •  Detection of unsanctioned package use and details of remediation activities related to vulnerabilities, licensing or deprecations

With an SBOM, organizations can easily identify which packages are being used in which applications and determine whether they're licensed properly. Moreover, it helps to manage security risks by enabling enterprises to quickly identify and address vulnerabilities that may exist in their software. By maintaining an accurate SBOM, organizations can mitigate the risks associated with using open-source packages, improving their overall security posture and ensuring compliance with licensing requirements.

5. Maintain developer education for security best practices  

Developers sometimes have a false sense of security regarding open-source projects. They may assume that an open codebase is immune to malicious software, but this is far from the case. When packages are installed from the public registry, they can potentially run scripts during installation. Transparency entails finding out which ones do that and either understanding why they do it or preventing it.

Taking the time and resources to educate developers makes a substantial impact. Avoiding solo, abandoned or unknown projects can go a long way toward improving security. Meanwhile, when packages are added, developers should do so with diligence and scrutiny by establishing tooling and workflows to ensure safety. Important steps include: 

  • Continuously investing in the development processes as well as developers, focusing on best practices for security and for source code 

  •  Being aware of the top ten WASPs and the common remediations

  • Adopting best practices around security, training and usage of all components in the software lifecycle

Lastly, establish processes for regular package updates and upgrades. Node.js has a strong release cycle in terms of addressing vulnerabilities and releasing new features. Likewise, any modifications to modules, whether it’s adding a new package or updating existing ones, should be easily reversible. In this sense, a Node.js application is no different from any other enterprise-grade software: Keep it cautiously updated. 

6. Evaluate packages before use  

It's essential for developers to stay up to date on the latest tools and processes for detecting issues early. One effective way to do this is to train developers on the use of lookup services before adding project dependencies. Just perusing the npm registry for clues can go a long way. Meanwhile, tools such as Socket and Snyk can help developers evaluate packages through release cadence, GitHub issues, maintainability and other factors. This due diligence helps identify potential vulnerabilities and helps developers make better decisions about which packages to use.

Additionally, there are industry-standard tools devs can use to scan packages before use. By using these tools, developers can detect vulnerabilities before packages are released into production, mitigating the risks of open-source packages and improving the overall security posture of applications.

7. Use tools when available to push detection "left" as much as possible  

There are also plenty of tools developers can use to push detection left, well before any code is committed to a repository. Devs can employ static code analysis tools to identify vulnerabilities and security issues in the codebase before deploying. Linting tools are a good example; these can do more than just enforce coding standards. 

Many development tools also have detection features built in. GitHub's Dependabot, for example, automatically checks for known vulnerabilities in a project's dependencies and notifies developers when updates or patches are available. GitHub also has a built-in code scanning feature that uses static code analysis to identify potential security issues and provide actionable feedback to developers. By leveraging these tools and features, developers can help ensure that their open-source software is more secure and less susceptible to attacks.

Adopting node package manager (npm) best practices

It never hurts to reiterate best practices when working with npm in an enterprise environment:

  • Be sure developers only use trusted packages. 

  • Make sure developers are correctly using Node.js version syntax in their package.json files and that they're using lock files appropriately. 

  • If devs are publishing packages to the npm registry, 2FA on npmjs.com is highly recommended.

  • Create and manage an organization account to help protect packages and brand identity. If an organization's name is in use, disputing its ownership of it is a straightforward process.

Though simple, these steps can be effective, especially when other open-source efforts are well-managed. By following these best practices, developers can help maintain the integrity and security of their Node.js packages.

Using open source and our shared responsibility

While open-source software is free to use, there are responsibilities inherent in using it. Whether it's an individual developer or one that represents an enterprise, it's important to use open-source software ethically. This entails taking the necessary steps to ensure the software that's used and distributed is reliable and secure. Becoming an active member of the open-source community, either by providing feedback and bug reports or by contributing code to open-source projects, is good practice. 

Node.js has come a long way in the last decade — technology is quickly becoming essential to enterprises. As a leader in technology, Capital One relies on it and other open-source tools to drive innovation and improve developer efficiency. But the ever-changing security landscape of web development requires a well-managed approach. 

Well-managed means following the same common sense usage policies and best practices that companies would apply to private enterprise software. Responsible usage, continued education, the establishment of open-source working groups and the use of the tools and techniques enterprises have at their disposal help ensure the security of open-source software. By implementing these best practices and the others outlined in this article, companies of every size can better manage the risks associated with open-source software while maximizing the benefits of Node.js and the JavaScript ecosystem.

Explore #LifeAtCapitalOne

Startup-like innovation with Fortune 100 capabilities.

Learn more

Steve Husak, Distinguished Engineer, Commercial Tech Architecture

Steve Husak has worked in several greenfield architectures over the course of his 30 years of industry experience ranging from kiosk systems, medical applications, gaming platforms to call-center applications. As a Distinguished Engineer, Steve has led the overall technical direction and architecture of the re-platform of a call-center agent servicing application for credit card servicing at Capital One. Steve drove the migration of the platform from a legacy technical stack and on-premise servers to a high-quality, fully cloud-based, completely federated platform built in Node.js and JavaScript technologies. Steve now works in Capital One's Commercial Banking unit focusing on the architecture of several systems utilized in underwriting and reporting in commercial lending. Steve has previously spoken at NodeConf EU, OpenJS World, FINOS externally as well as internally within Capital One on the re-architecting of monoliths to federated micro-frontend/microservice architectures as well as responsible usage of Node.js and open source software at enterprise scale.

Related Content