Most active commenters
  • ivan_gammel(5)
  • CaptainOfCoit(3)
  • pjmlp(3)

←back to thread

1208 points jamesberthoty | 52 comments | | HN request time: 1.825s | source | bottom
Show context
kelnos ◴[] No.45266878[source]
As a user of npm-hosted packages in my own projects, I'm not really sure what to do to protect myself. It's not feasible for me to audit every single one of my dependencies, and every one of my dependencies' dependencies, and so on. Even if I had the time to do that, I'm not a typescript/javascript expert, and I'm certain there are a lot of obfuscated things that an attacker could do that I wouldn't realize was embedded malware.

One thing I was thinking of was sort of a "delayed" mode to updating my own dependencies. The idea is that when I want to update my dependencies, instead of updating to the absolute latest version available of everything, it updates to versions that were released no more than some configurable amount of time ago. As a maintainer, I could decide that a package that's been out in the wild for at least 6 weeks is less likely to have unnoticed malware in it than one that was released just yesterday.

Obviously this is not a perfect fix, as there's no guarantee that the delay time I specify is enough for any particular package. And I'd want the tool to present me with options sometimes: e.g. if my current version of a dep has a vulnerability, and the fix for it came out a few days ago, I might choose to update to it (better eliminate the known vulnerability than refuse to update for fear of an unknown one) rather than wait until it's older than my threshold.

replies(35): >>45266995 #>>45267024 #>>45267360 #>>45267489 #>>45267600 #>>45267697 #>>45267722 #>>45267967 #>>45268218 #>>45268503 #>>45268654 #>>45268764 #>>45269143 #>>45269397 #>>45269398 #>>45269524 #>>45269799 #>>45269945 #>>45270082 #>>45270083 #>>45270420 #>>45270708 #>>45270917 #>>45270938 #>>45272063 #>>45272548 #>>45273074 #>>45273291 #>>45273321 #>>45273387 #>>45273513 #>>45273935 #>>45274324 #>>45275452 #>>45277692 #
1. wvh ◴[] No.45273513[source]
As a security guy, for years, you get laughed out of the room suggesting devs limit their dependencies and don't download half of the internet while building. You are an obstruction for making profit. And obviously reading the code does very little since modern (and especially Javascript) code just glues together frameworks and libraries, and there's no way a single human being is going to read a couple million lines of code.

There are no real solutions to the problem, except for reducing exposure somewhat by limiting yourself to a mostly frozen subset of packages that are hopefully vetted more stringently by more people.

replies(9): >>45273591 #>>45274145 #>>45274168 #>>45274297 #>>45275495 #>>45275734 #>>45276496 #>>45277631 #>>45279275 #
2. mgaunard ◴[] No.45273591[source]
I've always been very careful about dependencies, and freezing them to versions that are known to work well.

I was shocked when I found out that at some of the most profitable shops, most of their code is just a bunch of different third-party libraries badly cobbled together, with only a superficial understanding of how those libraries work.

3. p0w3n3d ◴[] No.45274145[source]
> You are an obstruction for making profit.

This explains a lot. Really, this is the great reason of why the society is collapsing as we speak.

"There should be no DRM in phones" - "You Are An Obstruction To Making Profit".

"People should own their devices, we must not disallow custom software on it" - "YAAOTMP"

"sir, the application will weigh 2G and do almost nothing yet, should we minify it or use different framework?" - "YAAOTMP".

"Madame, this product will cost too much and require unnecessary payments" - "YAAOTMP"

Etc. etc. Like in this "Silicon Valley" comedy series. But for real, and affecting us greatly.

replies(1): >>45275283 #
4. jen729w ◴[] No.45274168[source]
At my previous enterprise we had a saying:

Security: we put the ‘no’ in ‘innovation’.

5. 999900000999 ◴[] No.45274297[source]
The "solution" would be using a language with a strong standard library and then having a trusted 3rd party manually audit any approved packages.

THEN use artifactory on top of that.

That's boring and slow though. Whatever I want my packages and I want them now. Apart of the issue is the whole industry is built upon goodwill and hope.

Some 19 year old hacked together a new front end framework last week, better use it in prod because why not.

Occasionally I want to turn off my brain and just buy some shoes. The Timberland website made that nearly impossible last week. When I gave up on logging in for free shipping and just paid full price, I get an email a few days later saying they ran out of shoes.

Alright. I guess Amazon is dominant for a reason.

replies(5): >>45274427 #>>45274782 #>>45274799 #>>45275228 #>>45279075 #
6. silverliver ◴[] No.45274427[source]
This is the right answer. I'm willing to stick my head out and assert that languages with a "minimal" standard library are defective by design. The argument of APIs being stuck is mood with approaches like Rust's epocs or "strict mode".

Standard libraries should include everything needed to interact with modern systems. This means HTTP parsing, HTTP requests, and JSON parsing. Some laguages are excellent (like python), while some are half way there (like go), and some are just broken (Rust).

External libraries are for niche or specialized functionality. External libraries are not for functionality that is used by most modern software. To put your head in the ground and insist otherwise is madness and will lead to ridiculous outcomes like this.

replies(7): >>45275250 #>>45275311 #>>45275318 #>>45275441 #>>45275539 #>>45276844 #>>45277579 #
7. user3939382 ◴[] No.45274782[source]
I don’t recall hearing about constant supply chain attacks with CPAN
replies(2): >>45275026 #>>45275366 #
8. Loudergood ◴[] No.45274799[source]
I agree, it always seems to be NPM, and there's a reason for that.
9. bleuarff ◴[] No.45275026{3}[source]
Because it's never been considered an interesting target, compared to npm's reach?
10. ivan_gammel ◴[] No.45275228[source]
Java + Spring Boot BOM + Maven Central (signed jars) does fit the description.
11. CaptainOfCoit ◴[] No.45275250{3}[source]
> External libraries are not for functionality that is used by most modern software.

Where do you draw the line though? It seems like you mostly spend your time writing HTTP servers reading/writing JSON, but is that what everyone else also spends their time doing? You'll end up with a standard library weighing GBs, just because "most developers write HTTP servers", which doesn't sound like a better solution.

I'm willing to stick my head the other way, and say I think the languages today are too large. Instead, they should have a smaller core, and the language designed in a way that you can extend the language via libraries. Basically more languages should be inspired by Lisps and everything should be a library.

replies(2): >>45275344 #>>45278316 #
12. ivan_gammel ◴[] No.45275283[source]
Death comes to corp CEO, he screams YAAOTMP, death leaves shocked. Startup CEO watches the scene. His jedi sword turns from blue to red.
13. Ygg2 ◴[] No.45275311{3}[source]
> Standard libraries should include everything needed to interact with modern systems.

So, databases? Which then begs the question, which - Postgres, MySQL, SQLite, MS SQL, etc.? And some NoSQL, because modern systems might need it.

That basically means you need to pull in everything and the kitchen sink. And freeze it in time (because of backwards compatibility). HTML, HTTP parsing, and SHA1024 are perfectly reasonable now; wait two decades, and they might be as antiquated as XML.

So what your language designers end up, is having to work on XML parsing, HTTP, JSON libraries rather than designing a language.

If JS way is madness, having everything available is another form of madness.

replies(1): >>45277331 #
14. Arcterus ◴[] No.45275318{3}[source]
> Standard libraries should include everything needed to interact with modern systems.

This is great when the stdlib is well-designed and kept current when new standards and so on become available, but often "batteries included" approaches fail to cover all needs adequately, are slow to adopt new standards or introduce poorly designed modules that then cannot be easily changed, and/or fail to keep up-to-date with the evolution of the language.

I think the best approach is to have a stdlib of a size that can be adequately maintained/improved, then bless a number of externally developed libraries (maybe even making them available in some official "community" module or something with weaker stability guarantees than the stdlib).

I find it a bit funny that you specifically say HTTP handling and JSON are the elements required when that's only a small subset of things needed for modern systems. For instance, cryptography is something that's frequently required, and built-in modules for it often suck and are just ignored in favor of external libraries.

EDIT: actually, I think my biggest issue with what you've said is that you're comparing Python, Go, and Rust. These languages all have vastly different design considerations. In a language like Python, you basically want to be able to just bash together some code quickly that can get things working. While I might dislike it, a "batteries included" approach makes sense here. Go is somewhat similar since it's designed to take someone from no knowledge of the language to productive quickly. Including a lot in the stdlib makes sense here since it's easier to find stuff that way. While Rust can be used like Python and Go, that's not really its main purpose. It's really meant as an alternative to C++ and the various niches C/C++ have dominated for years. In a language like that, where performance is often key, I'd rather have a higher quality external library than just something shoved into the stdlib.

replies(3): >>45275674 #>>45285262 #>>45286238 #
15. smaudet ◴[] No.45275344{4}[source]
I don't think things being libraries (modular) is at odds with a standard library.

If you have a well vetted base library, that is frequently reviewed, under goes regular security and quality checks, then you should be minimally concerned about the quality of code that goes on top.

In a well designed language, you can still export just what you need, or even replace parts of that standard library if you so choose.

This approach even handles your question: as use cases become more common, an active, invested* community (either paying or actively contributing) can add and vet modules, or remove old ones that no longer serve an active purpose.

But as soon as you find yourself "downloading the web" to get stuff done, something has probably gone horribly wrong.

replies(1): >>45275618 #
16. AdamN ◴[] No.45275366{3}[source]
That was a different era. The velocity of change is 100x now and the expectation for public libraries to do common things is 100x higher as well.
replies(1): >>45276159 #
17. jajko ◴[] No.45275441{3}[source]
Java is around for much longer, has exactly same architecture re transitive dependencies, yet doesn't suffer from weekly attacks like these that affect half of the world. Not technically impossible, yet not happening (at least not at this scale).

If you want an actual solution, look for differences. If you somehow end up figuring out its about type of people using those, then there is no easy technical solution.

18. epage ◴[] No.45275495[source]
This comes across as not being self-aware as to why security as laughed out of rooms: I read this as you correctly identifying some risks and said only offered the false-dichotomouy of solutions of "risk" and "no risk" without talking middle grounds between the two or finding third-ways that break the dichotomy.

I could just be projecting my own bad experiences with "security" folks (in quotes as I can't speak to their qualifications). My other big gripe is when they don't recongnize UX as a vital part of security (if their solution is unsuable, it won't be used).

replies(2): >>45275694 #>>45278882 #
19. goku12 ◴[] No.45275539{3}[source]
> This is the right answer. I'm willing to stick my head out and assert that languages with a "minimal" standard library are defective by design.

> Standard libraries should include everything needed to interact with modern systems. This means HTTP parsing, HTTP requests, and JSON parsing.

There is another way. Why not make the standard library itself pluggable? Rust has a standard library and a core library. The standard library is optional, especially for bare-metal targets.

Make the core library as light as possible, with just enough functionality to implement other libraries, including the interfaces/shims for absolutely necessary modules like allocators and basic data structures like vectors, hashmaps, etc. Then move all other stuff into the standard library. The official standard library can be minimal like the Rust standard library is now. However, we should be able to replace the official standard library with a 3rd party standard library of choice. (What I mean by standard library here is the 'base library', not the official library.) Third party standard library can be as light or as comprehensive as you might want. That also will make auditing the default codebase possible.

I don't know how realistic this is, but something similar is already there in Rust. While Rust has language features that support async programming, the actual implementation is in an external runtime like Tokio or smol. The clever bit here is that the other third party async libraries don't enforce or restrict your choice of the async runtime. The application developer can still choose whatever async runtime they want. Similarly, the 3rd party standard library must not restrict the choice of standard libraries. That means adding some interfaces in the core, as mentioned earlier.

replies(1): >>45286400 #
20. TylerE ◴[] No.45275618{5}[source]
IMO Python 2 was rhetorical gold standard for getting the std lib right. Mostly batteries included, but not going totally insane with it.
21. JoBrad ◴[] No.45275674{4}[source]
The tradeoff of “batteries included” vs not is real: Python developers famously reach for community libraries like requests right away to avoid using the built-in tooling.
replies(2): >>45276962 #>>45279966 #
22. romaniv ◴[] No.45275694[source]
I've been a web developer for over two decades. I have specific well-tested solutions for avoiding external JS dependencies. Despite that, I have the exact same experience as the above security guy. Most developers love adding dependencies.
replies(1): >>45276366 #
23. CerebralCerb ◴[] No.45275734[source]
The post you replied to suggested a real solution to the problem. It was implemented in my current org years ago (after log4j) and we have not been affected by any of the malware dependencies that has happened since.
24. Sophira ◴[] No.45276159{4}[source]
Perl and CPAN are still a thing, much as people would like to think otherwise.
25. user34283 ◴[] No.45276496[source]
Your proposed solution does not work for web applications built with node packages.

Essentials tools such as Jest add 300 packages on their own.

You already have hundreds to thousands of packages installed, fretting over a few more for that DatePicker or something is pretty much a waste of time.

26. 999900000999 ◴[] No.45276844{3}[source]
It's not an easy problem to solve.

Doing it the right way would create friction, developers might need to actually understand what the code is doing rather than pulling in random libraries.

Try explaining to your CTO that development will slow down to verify the entire dependency chain.

I'm more thinking C# or Java. If Microsoft or Oracle is providing a library you can hope it's safe.

You *could* have a development ecosystem called Safe C# which only comes with vetted libraries and doesn't allow anything else.

I'm sure other solutions already exist though.

replies(2): >>45277609 #>>45278764 #
27. Natfan ◴[] No.45276962{5}[source]
I wasn't even aware there _was_ built-in tooling...
28. ivan_gammel ◴[] No.45277331{4}[source]
It is not madness. Java is a good example of rich and modular standard library. Some components of it are eventually deprecated and removed (e.g. Applets) and this process takes long enough. Its standard library does include good crypto and http client, database abstraction API (JDBC) which is implemented by database drivers etc.
replies(2): >>45278010 #>>45278133 #
29. pjmlp ◴[] No.45277579{3}[source]
Spot on, I rather have a Python, Java,.NET,.. standard library, that may have a few warts, but works everywhere there is full compliant implementation, than playing lego, with libraries that might not even support all platforms, and be more easily open to such attacks.

Is java.util.logging.Logger not that great?

Sure, yet everyone that used it had a good night rest when Log4J exploit came to be.

replies(1): >>45278516 #
30. pjmlp ◴[] No.45277609{4}[source]
Why?

This is a standard practice in most places I have worked, CI/CD only allowed to use internal repos, and libraries are only added after clearance.

replies(1): >>45278265 #
31. awaythrow999 ◴[] No.45277631[source]
Agree on the only solution being reducing dependencies.

Even more weird in the EU where things like Cyber Resilience Act mandate patching publicly known vulnerabilities. Cool, so let's just stay up2date? Supply-chain vuln goes Brrrrrr

32. Ygg2 ◴[] No.45278010{5}[source]
Yeah, and Java was always corporately funded, and to my knowledge no one really used neither the http client nor the XML parser. You basically have a collection of dead weight libs, that people have to begrudgingly maintain.

Granted some (JDBC) more useful than the others. Although JDBC is more of an API and less of a library.

replies(1): >>45278260 #
33. koakuma-chan ◴[] No.45278133{5}[source]
My favourite is java.awt.Robot
34. ivan_gammel ◴[] No.45278260{6}[source]
HttpClient is relatively new and getting HTTP/3 support next spring, so it’s certainly not falling into the dead weight category. You are probably confusing it with an older version from Java 1.1/1.4.

As for XML, JAXP was a common way to deal with it. Yes, there’s Xstream etc, but it doesn’t mean any of standard XML APIs are obsolete.

35. brazzy ◴[] No.45278265{5}[source]
Except that "clearance" invariably consists of bureaucratic rubber stamping and actually decreases security by making it harder and slower to fix newly discovered vulnerabilities.
replies(1): >>45278308 #
36. pjmlp ◴[] No.45278308{6}[source]
Depends on the skills of the respective DevOps security team.

There are also tools that break CI/CD based on CVE reports from existing dependencies.

37. groby_b ◴[] No.45278316{4}[source]
> everything should be a library.

That's exactly npm's problem, though. What everybody is avoiding to say is that you need a concept of "trusted vendors". And, for the "OSS accelerates me" business crowd, that means paying for the stuff you use.

But who would want that when you're busy chasing "market fit".

replies(1): >>45278443 #
38. CaptainOfCoit ◴[] No.45278443{5}[source]
> That's exactly npm's problem, though.

I don't think that's the problem with npm. The problem with npm is that no packages are signed, at all, so it ends up trivial for hackers to push new package versions, which they obviously shouldn't be able to do.

replies(1): >>45279111 #
39. ivan_gammel ◴[] No.45278516{4}[source]
slf4j is probably more common now than standard Logger, and it was a good night for those who used Logback as implementation.
40. Shorel ◴[] No.45278764{4}[source]
> Doing it the right way would create friction, developers might need to actually understand what the code is doing rather than pulling in random libraries.

Then let's add friction. Developers understanding code is what they should be doing.

CTOs understand the high cost of ransomware and disruption of service.

41. bongodongobob ◴[] No.45278882[source]
This is how our security lead is. "I've identified X as a vulnerability, recommended remediation is to remove it." "We literally can't." He pokes around finding obscure vulnerabilities and recommends removing business critical software, yet we don't have MFA, our servers and networking UIs are on the main VLAN accessable by anyone, we have no tools to patch third party software, and all of our root passwords are the same. We bring real security concerns to him like this, and they just get backlogged because his stupid tools he runs only detect software vulns. It's insanity.
42. nonethewiser ◴[] No.45279075[source]
>Some 19 year old hacked together a new front end framework last week, better use it in prod because why not.

The thing is, you don't have to be this undiscerning to end up with tons of packages.

Let's init a default next.js project. How many dependencies are there?

react, react-dom, next, typescript, @types/node, @types/react, @types/react-dom.

OK so 7... seems like a lot in some sense but its still missing many reasonable dependencies. Some sort of styling solution (tailwind, styled components, etc). Some sort of http client or graphql. And more. But lets just use the base dependencies as an example. Is 7 so bad? Maybe, maybe not, but you need to go deeper. How many packages are there?

55. What are they? I have no idea, go read the lock file I guess.

All of this while being pretty reasonable.

43. carols10cents ◴[] No.45279111{6}[source]
Since Shai-Hulud scanned maintainers' computers, if the signing key was stored there too (without a password), couldn't the attackers have published signed packages?

That is, how does signing prevent publishing of malware, exactly?

replies(3): >>45283644 #>>45287865 #>>45290065 #
44. ozim ◴[] No.45279275[source]
Package registries should step up. They are doing some stuff but still NPM could do more.
45. bigstrat2003 ◴[] No.45279966{5}[source]
And yet, there are times where all I've had access to was the stdlib. I was damn glad for urllib2 at those times. It's worth it to have a batteries included stdlib, even if parts of it don't wind up being the most commonly used by the community.
replies(1): >>45283633 #
46. yawaramin ◴[] No.45283633{6}[source]
The fact that there is a 'urllib2' implies that there's a 'urllib', which tells us something pretty important about the dangers of kitchen-sink standard libraries.
47. yawaramin ◴[] No.45283644{7}[source]
How did Shai-Hulud get access to maintainers' computers?
48. auraham ◴[] No.45285262{4}[source]
Related: Rust Dependencies Scare Me [1]

[1] https://vincents.dev/blog/rust-dependencies-scare-me/

49. wolvesechoes ◴[] No.45286238{4}[source]
But nothing prevents a language to have rich and OPTIONAL stdlib, so that devs can choose different solutions without linking bunch of junk they do not use.

Really, good stdlib still allows you to use better suited 3rd party libraries. Lack of good stdlib doesn't add anything.

50. qcnguy ◴[] No.45286400{4}[source]
This is the philosophy used by the Java world. Big parts of the standard library are plugin-based. For example, database access (JDBC), filesystem access (NIO), cryptography (JCA). The standard library defines the interfaces and sometimes provides a default implementation, but it can be extended or replaced.

It works well, but the downside of that approach is people complaining about how abstract things are.

51. CaptainOfCoit ◴[] No.45287865{7}[source]
> if the signing key was stored there too (without a password), couldn't the attackers have published signed packages?

Yeah, of course. Also if they hosted their private key for the signature on their public blog, anyone could use it for publishing.

But for the sake of the argument, why don't we assume people are correctly using the thing we're talking about?

52. lelanthran ◴[] No.45290065{7}[source]
In past comments I said that a quick win would be to lean on certificates; those can't easily be forged once a certificate is accepted.