11 ms·
How do we even mitigate against these types of supply-chain attacks Don’t import thousands of modules from third parties just to write a simple web app. If you
by grey-area 5y ago
How do we even mitigate against these types of supply-chain attacks
Don’t import thousands of modules from third parties just to write a simple web app. If you have 10 stable dependencies it’s no problem to vendor them and vet changes. If you have 10k you’ve entirely given up on any pretence of security.
- vosper 5y agoPeople don't directly import thousands of modules. It's actually a lot closer to your "10 stable dependencies". But those dependencies have dependencies that have dependencies. It's a little hard to point the finger at application developers here, IMO.
- pdonis 5y ago> It's a little hard to point the finger at application developers here, IMO. I disagree. Any application developer who seriously thinks that they only have 10 dependencies if they're only importing directly 10 dependencies should not be an application developer in the first place.
- IggleSniggle 5y agoYou sure about that? Even if you’re writing just for a vetted distribution of an OS, and you write code with zero explicit dependencies, you still have much more than zero dependencies. It’s turtles all the way down. The key is to have an entire ecosystem that you can, to some degree more or less, trust.
- marcus_holmes 5y agoNo. we've been shouting warnings for years. There have been dozens, if not hundreds of threads on HN alone warning of supply-chain security threats. At this point if you're not actively auditing your dependencies, and reducing all of them where you can, then you're on the wrong side of history and going down with the Titanic. The frank truth is that including a dependency is, and always has been, giving a random person from the internet commit privileges to prod. The fact that "everyone else did it" doesn't make it less stupid.
- erulabs 5y ago> The frank truth is that including a dependency is, and always has been, giving a random person from the internet commit privileges to prod I mean, no. This is hyperbole at best and just wrong at median. A system of relative trust has worked very well for a very long time - Linus doesn’t have root access to all our systems, even if we don’t have to read every line of code.
- chha 5y agoLinus doesn't have root access to our systems for several reasons. One of them is the fact that we get the actual source code, and not just a compiled blob doing "something". Another is the fact that they have at least some level of reviews wrt who can commit code, although this isn't perfect as the case with the University of Minnesota proved. Npm on the other hand is much, much worse. Anyone can publish anything they want, and they can point to any random source code repository claiming that this is the source. If we look at how often vulnerable packages are discovered in eg. npm, I'd argue that the current level of trust and quality aren't sustainable, partly due to the potentially huge number of direct and transitive dependencies a project may have. Unless you start to review the actual component you have no way to verify this, and unlike the Linux kernel there is no promise that anyone has ever reviewed the package you download. You can of course add free tools such as the OWASP Dependency Check, but these will typically lag a bit behind as they rely on published vulnerabilities. Other tools such as the Sonatype Nexus platform is more proactive, but can be expensive.
- elevader 5y agoMaybe this is arguing semantics but unless you run something like Gentoo you will most likely get the linux kernel as a binary blob contained in a package your distribution provides. There isn't really any guarantee that this will actually contain untampered linux kernel sources (and in case of something like RHEL it most likely doesn't because of backports) unless you audit it, which most people won't do (and maybe can't do). So, in princpile at least, this isn't really that much better than the node_modules situation. Security and trust are hard issues and piling on 100s of random js dependencies sure doesn't help but you either build everything yourself or you need to trust somebody at some point.
- pdonis 5y ago> Even if you’re writing just for a vetted distribution of an OS, and you write code with zero explicit dependencies, you still have much more than zero dependencies. Sure, the entire OS is a dependency. Nothing I said contradicts that. And yes, every application developer should be aware of what they are depending on when they write software for a particular OS. > The key is to have an entire ecosystem that you can, to some degree more or less, trust. You don't necessarily need to trust an entire ecosystem, but yes, every dependency you have is a matter of trust on your part; you are trusting the dependency to work the way you need it to work and not to introduce vulnerabilities that you aren't aware of and can't deal with. Which is why you need to be explicitly aware of every dependency you have, not just the ones you directly import.
- IggleSniggle 5y agoI am actually not sure if this is possible, while also accepting security updates etc from my OS distributor? How do you literally personally vet every line of code that gets run directly AND indirectly by your application, and still have time to write an application? I’m okay with saying, “I trust RHEL to be roughly ok, just understand the model and how to use it, and keep my ear to the ground for the experts in case something comes up.” At the level of npm, I feel roughly the same about React. I don’t trust it quite as much, but I’m also not going to read every code change. I’ll read a CHANGELOG, sure, and spelunk through the code from time to time, but that’s not really the same. I’ll probably check out their direct dependencies the first time, but that’s it. I actually don’t know how you could call yourself an application developer in most ecosystems and know every single dependency you actually have all the way down, soup to nuts. Heck, there are dependencies that I accept so that my code will run on machines that I have no special knowledge of, not just my own familiar architecture. I accept them because I want to work on the details of my application and have it be useful on more than just my own machine. Edit for clarity: I agree with almost everything you’re suggesting as sensible. Just not with your conclusion: that you’re not a “real” application developer if you don’t know all of your dependencies
- pdonis 5y ago> I am actually not sure if this is possible, while also accepting security updates etc from my OS distributor? Accepting the OS as a dependency includes the security updates from the OS, sure. > How do you literally personally vet every line of code Ah, I see, you think "understanding the dependency" requires vetting every line of code. That's not what I meant. What I meant is, if you use library A, and library A depends on libraries B, C, and D, and those libraries in turn depend on libraries E, F, G, H, I, etc. etc., then you don't just need to be aware that you depend on library A, because that's the only one you're directly importing. You need to be aware of all the dependencies, all the way down. You might not personally vet every line of code in every one of them, but you need to be aware that you're using them and you need to be aware of how trustworthy they are, so you can judge whether it's really worth having them and exposing your application to the risks of using them. > I’ll probably check out their direct dependencies the first time, but that’s it. So if they introduce a new dependency, you don't care? You should. That's the kind of thing I'm talking about. Again, you might not go and vet every line of code in the new dependency, but you need to be aware that it's there and how risky it is. > I actually don’t know how you could call yourself an application developer in most ecosystems and know every single dependency you actually have all the way down, soup to nuts. If you're developing using open source code, information about what dependencies a given library has is easily discoverable. If you're developing for a proprietary system, things might be different.
- deleted 5y ago[deleted]
- nitwit005 5y agoI mean, you say that, but the practice of pulling in so many dependencies is fairly recent. It wasn't even possible for most projects before everyone had fast internet.
- dpweb 5y agoSome of the comments in this thread are wild. Huge dependency trees are bad pattern, plain and simple. The problem isn’t only ridiculous amounts of untrusted code, but thousands of new developers of the last 10 years who think this is the way to write reliable code. Never acknowledged the risks of having everyone write your code for you, and overestimate how unique and interesting their apps are. If you must participate in this madness, static analysis tools exist to scan your 10000 dependencies, taking security seriously is the issue.
- deleted 5y ago[deleted]
- noway421 5y agoMost of those dependencies have well defined, stable api. They use or at least try to follow semver. And you're probably only hitting about 10% of your dependencies on the critical path you're using, meaning that a lot of potentially vulnerable code is never executed. I get the supply chain attacks. I get that you have a tree of untrusted javascript code that you're executing in your app, on install, on build and in runtime. But there's also Snyk and Dependabot which issue you alerts when your dependency tree has published CVEs. We can talk about alert fatigue, but to be honest, I feel more secure with my node_modules folder than I do with my operating system and plethora of DLLs it loads. I don't wanna turn this into a whataboutism argument, but at some point you gotta get to work, write some code and depend on some libraries other people have written.
- laurent92 5y ago> Snyk and Dependabot Wait, I’m not safe using “npm audit”?
- grey-area 5y agoSemver will not save you.
- ptx 5y ago> And you're probably only hitting about 10% of your dependencies on the critical path you're using, meaning that a lot of potentially vulnerable code is never executed. If a dependency has been compromised it doesn't matter if its code is actually used, since it can include a lifecycle script that's executed at install-time, which was apparently the mechanism for the recent ua-parser-js exploit.
- grey-area 5y agoThis is the direct result of the culture of tiny dependencies in JS and some other languages, but not all ecosystems are like this. If you choose to use node, this is where you end up, but it was a choice. Many languages have a decent standard library which covers most of the bases, so it’s possible to have a very restricted set of dependencies.
- jschrf 5y agoUnfortunately for frontend and the Node ecosystem, it's too late to try and put the toothpaste back in the tube. Hopefully Deno helps with this pain point.
- shadowgovt 5y agoThat's going to be incompatible with writing interesting software on the web, unless we want to just hand the problem over to a handful of big players who can afford to hand-vet 10,000 dependencies. The reason packages are so big is the complexity for an interesting app is irreducible. People don't import thousands of modules for fun; they do it because simple software tends towards requiring complex underpinning. Consider the amount of operating system that underlies a simple "Hello, world!" GUI app. And since the browser-provided abstractions are trash for writing a web app, people swap them out with frameworks. I'm working on a React app right now where I've imported about a dozen dependencies explicitly (half of which are TypeScript @type files, so closer to a half-dozen). The total size of my `node_modules` directory is closer to a couple hundred packages. It's 35MB of files. And no, I couldn't really leave any of them out to do the thing I want to do, unfortunately.
- rhizome 5y agoI have to think there's a lot of YAGNI going on, dependencies that are included to be a better version of native functionality. A faster JSON parser, say, with I dunno, 20 dependencies (a count which may further extend within those deps) for something where slow JSON parsing has not yet become an issue. I think there's a lot of "academic" inclusions out there like this.
- endless1234 5y agoMy experience working on tens of front end projects is the complete opposite. Nobody is adding dependencies just for the fun of it, or because you might need it in a year. You add a dependency because you need some functionality and there is no time/budget to re-do it in house - not to mention that if it's a well-supported library with, for example, hundreds of thousands of users, it's unlikely you could even make it better.
- cxr 5y ago> there is no time/budget to re-do it in house What are the actual time cost savings when you take the total costs into consideration?[1][2] What would it look like if you didn't implement an app by stringing together dozens/hundreds/thousands of third-party modules implemented bottom-up, but instead took control of the whole thing top-down?[3] 1. https://jvns.ca/blog/2021/11/15/esbuild-vue/ https://jvns.ca/blog/2021/11/15/esbuild-vue/ 2. https://news.ycombinator.com/item?id=24495646 https://news.ycombinator.com/item?id=24495646 3. https://www.teamten.com/lawrence/programming/write-code-top-down.html https://www.teamten.com/lawrence/programming/write-code-top-...
- ncc-erik 5y agoI only imported 10 dependencies, but those 10 dependencies each had 10 dependencies which each had 10 dependencies which each had 10 dependencies and all of the sudden I'm at 10k dependencies again...
- nirvdrum 5y agoThe transitive dependency chain should be part of your evaluation of a library. Frameworks are special cases, for sure. But if you’re adding a dependency and it adds 10,000 new entries to your lock file, that should be taken into consideration during your library selection process. Likewise, when upgrading dependencies, you should watch how much of the world gets pulled in. That said, I don’t know what the answer is for JS. There are too many dependency cycles that make auditing upgrades intractable. If you’re not constantly upgrading libraries, you’ll be unable to add a new one because it probably relies on a newer version of something you already had. In most other ecosystems, upgrading can be a more deliberate activity. I tried to audit NPM module upgrades and it’s next to impossible if using something like Create React App. The last time I tried Create React App, yarn-audit reported ~5,000 security issues on a freshly created app. Many were duplicates due with the same module being depended on multiple times, but it’s still problematic.
- edgyquant 5y agoWhat’s the alternative? Writing everything in house? I think a better solution would be a better dependency installer/resolver that is as secure as possible.
- evilduck 5y agoFrameworks and library authors could stand to do more in-house. It's also on devs to vet a library for maintenance concerns like sprawling dependencies.
- lawl 5y ago> What’s the alternative? Don't use the popular hype garbage. Yes, I realize that may not be an option for a lot of people professionally. But I believe if you actually spend some time on due diligence for any dependency you consider adding, you can significantly reduce the number of untrusted deps you pull in. One of the problems of course is that javascript exacerbates this problem somewhat by not having a comprehensive standard library. But whenever I look for go libraries, go.sum is usually one of the first files I click to check how much garbage it pulls in.
- noway421 5y agoStandard library is a dependency too and can have bugs in it. What's better - having stdlib tied to the runtime release schedule or having a lot of micro libraries on their own rolling release schedule which can quickly release security patches? I agree, having those dependencies authored by Node.js Foundation itself will yield higher level of trust. But we're all human, and one can argue earnest open source developers have better aligned incentives than a randomly selected Node.js Foundation employee. I honestly am not sure I fully agree with what I've just written above either. But one thing I would want to pinpoint: those things are NOT black and white. The specific set of trade offs the Node.js ecosystem fallen into might look accidental and inadequate. But I think it's fairly reasonable.
- grey-area 5y agoYes using a standard library is better. It is more stable, trustworthy and maintained by a small group of people.
- krono 5y agoRecently Node 16 LTS cycle started. One month and a few days before the carry-over, a super controversial package titled `coredeps` [0] was officially declared a core module and has been bundled with all official distributions since. The NodeJS team refuses to discuss NPM because it's a separate 3rd party. And yet.... this NodeJS Core module comes pre-installed as a global NPM package. We're just getting started. This module installs or even reinstalls any supported package manager when you execute a script with a name that would match any that they'd recognise. Opt-in for only a short period, and intending to expand beyond package manager installations. Amidst all that's been going on, NPM (Nonstop Published Moments) is working on a feature that silently hijacks user commands and installs foreign software. The code found in those compromised packages operated in a similar manner and was labeled a critical severity vulnerability. The following might actually make you cry. Of these third party remote distributions it's downloading, the number of checksum, keys, or even build configurations that are being verified is 0. The game that Microsoft is playing with their recent acquisitions here is quite clear, but there's too much collateral damage. [0] https://github.com/nodejs/corepack#readme https://github.com/nodejs/corepack#readme
- arcatek 5y agoTo reiterate on what sibling comments said, I'm the one who spawned the discussion and implementation of Corepack, and npm remained largely out of it; the push mostly came from pnpm and Yarn. Additionally, unlike other approaches, Corepack ensures that package manager versions are pinned per project and you don't need to blindly install newest ones via `npm i -g npm` (which could potentially be hijacked via the type of vulnerability discussed here). It intends to make your projects more secure, not less.
- krono 5y agoIf anything this makes it worse. - No security checks are present in the package manager download and installation process so there are still no guarantees. - Existing installations of package managers are automatically overwritten when the user calls their binary. What if this was a custom compilation or other customisations were made? - This solution does a lot more behind the scenes than just run that yarn command that the user asked for but hand't installed. - Why not simply notify the user when their package manager isn't installed or only allow it with a forced flag? (As has been suggested uncountable times by numerous people anywhere this topic came up over the years.) Disrespecting user autonomy, capacity to self-regulate, and ownership over their machine and code is not the way. Edit: Formatting
- HWR_14 5y agoHow do you police what your imports import? Serious question. Let's say I'm building a Discord app (as I want to do.) Well, either NPM or Python PIP to get one module - the discord module. But who knows how safe what it imports is. That's the point. Are there stable dependencies from reputable companies that do the things I want without me vetting 10k submodule imports?
- skinkestek 5y agoI somewhat naively assume that at least if I use plain React or Angular then - someone at Facebook or Google has vetted the dependcy graph for those - I also assume they have internal Snyk-like tools - I also assume other users have similar tools so someone should catch it. When it comes to anything else I often look into what it pulls in. Also I keep an eye on the yarn.lock-file in pull requests.
- ptx 5y agoThis requires that you're pulling in only exactly the same versions of those dependencies as those that Facebook and Google have vetted. Is there a way to do that?
- filoeleven 5y ago> so someone should catch it. Just a week or two ago, a malicious NPM package was published which, for the hour or so that it was up, would be pulled in by any installation of create-react-app, since somewhere in the dependency tree it was specified with “^” to allow for minor updates. Any machine that ran “npm -i” with CRA or who knows how many other projects during that hour may have compromised credentials. 1 hour to find and unpublish the malicious package is a fast turnaround time, so someone was watching and that’s great. But any NPM tree that includes anything other than fully-specified and locked versions all the way down the tree is just waiting for the next shoe to drop.
- HWR_14 5y agoSo my specific usecase (write a Discord bot) has the solution of "write everything from scratch" or "don't use JS"? That's kinda what I assumed, but "only run code that have been signed off on by a major company" is kinda a shitty solution.
- adolph 5y agoMaybe 10 stable dependencies without dependencies? Otherwise it's dependencies all the way down. Is vendoring in a dependency just slowing things down? Slows down development and bakes existing attacks in longer.
- veeti 5y agoUnfortunately most modern JavaScript tooling has made this very difficult. Before you even have a "hello world" app running create-react-app et al. will install literally a thousand random packages. It's already over.
- deleted 5y ago[deleted]