Two Million Threats
Assurance and security in the Node.JS ecosystem
All it took to bring down millions of Node.js applications was one click.
Like many open source development ecosystems, node.js relies of the extensive reuse of code to expedite development. In the giant npm repository, which includes more than 700,000 separate components, code packages often call on other packages in order to function as designed. And these dependencies change frequently: Together, there were 2,029,645 updates in 2017 to these packages. This interdependency is both hugely beneficial and also a source of fragility.
And, unbeknownst to most developers, left-pad has been reused by many, many node packages, often indirectly by packages that developers depend on. When left-pad was deleted, every downstream package which relied upon it directly or indirectly failed to install - leaving thousands with dead applications. All because one developer pushed one button.
Although the damage was reversed, and left-pad restored to the npm, the message was clear: modularity and reuse are powerful tools for developers, but they can leave ecosystems, like node, vulnerable.
This is a problem that ISR’s Christian Kästner is taking on. “We’re not saying that package authors are intentionally malicious,” he notes, “only that they could be and that there are significant security concerns given the size of the attack surface and low levels of quality assurance.”
So how do you secure an ecosystem with millions of line of code across hundreds of thousands of packages? Moreover, how do you secure this environment without stifling the free sharing and exchange of resources that has made these distributed modes of production so powerful? Kästner believes that the right approach is to focus initially on the smallest, most innocuous packages - like “left-pad” - which larger, more complex packages rely upon.
Many of these small packages perform very simple functions that do not require access to the internet, or file system privileges. “For the simple things, like Left Pad and many utilities, that lots of people are using, we can make sure that we don’t make it exploitable easily,” Kästner explains. “Even if somebody tries to do something malicious with those packages, it would be very difficult to gain access to or send data anywhere. As soon as a package which previously didn’t require any outside access attempted to connect to internet, access the file system, or connect to another module, you’d be notified of the change and the package would be flagged.”
But how would Kästner’s system know which packages required access permissions? Simple: A manifest. Many applications - for example, apps in the GooglePlay store - are required to submit a permissions manifest when they are uploaded. Kästner proposes that, in component repositories such as npm, permissions can be inferred from the code. These suggested permissions would then be provided to developers to confirm or amend prior to submitting their package to the repository. Developers who decide to depend on a package can then review whether the permissions the package requests make sense and would be notified if those permissions should change.
While these may seem like obvious or simple fixes to a very grand technical problem, the beauty is in its simplicity, Kästner believes. “Node isn’t the only ecosystem that is experiencing this threat from malicious package updates. Python, Ruby, and others are almost as reliant of modular and reusable code. Since approximately 32% of the packages on Node are simple in nature and require very few access permissions, the hope is that we can show that with a few relatively minor changes to the ecosystem supply-chain, you can greatly reduce the overall attack surface and make the entire ecosystem more secure.”