Ideas (shoot them down): - Somehow tie keys to location. - Require two-step verification for all commits for packages with over 1000 downloads. (Assuming their phone isn't compromised if the keys are).
https://reproducible-builds.org/docs/buy-in/
When it comes to verifying this, we need to have independent rebuilders that build these packages reproducibly, and can attest these rebuilds in a secure manner. I have been working with NYU Secure System Labs to try provide this to debian packages and we currently have a PoC for such a system.
https://reproducible-builds.org/docs/sharing-certifications/
https://ssl.engineering.nyu.edu/blog/2019-01-18-in-toto-pari...
But I think this goes in the right direction.
Of course, this adds a big deliberate barrier to participation - newcomers have to get their key signed by an existing Debian developers. There are real security/usability tradeoffs, and at the moment people seem to have default-chosen "anyone can add packages really easily", resulting in a Cambrian explosion of packages.
A non-exhaustive list of things that could be done...
- Improve repository security (e.g. stronger authentication requirements). Problem here is most of the repositories are non-profit and this costs money. Also there's a risk that if you increase friction for developers, they'll go elsewhere.
- Require library signing. This has some potential benefits (may even have stopped this attack) but again increased friction for developers and management overhead for repositories.
- Curation of libraries. Actually pay some people to review the code in the libraries. This doesn't scale easily when you consider the volume that places like NPM have.
- Sandbox code modules
If a library doesn't need any permissions, and it's not granted any, then attempts to e.g. access the filesystem or network will throw exceptions. The JVM can do this, but it's not well documented how to use it.
Found the blanket statement for npm.
How about instead of reviewing 1 library of 10k lines that does everything, you review 10 focused modules for a total of 1k lines?
Also modules like left-pad don’t change that often so you probably have to review only changes in the top modules.
We need to stop this mentality that dependency count should be low. Look at total LOC and you’ll probably find that it’s not as bad as people like to paint it.
1) Signing should always happen. Publish time + hashes of external resources should be taken into account to prevent meddling with things after the fact.
2- a much harder solution) Don't use so many libraries.
In this way I think it's borderline impossible. Of course this vuln targeted `bootstrap-sass`.. it's basically a default gem for new rails installations since bootstrap is so commonly used.
Actually, rails 6.0 not only installs dependencies for you upon generating a new app, but it downloads yarn and installs 602 dependencies too.
It's a miracle we do anything as programmers.
But now you will move at the pace of a bacteria on a snail. But since the company will probably introduce vulnerability bugs in the code they write, it is probably not a very good idea.
We are using open source and free packages to save time and move fast. Security and speed/usability have tradeoffs.
The paranoid will do everything in their knowledge to protect themselves but they will move slowly. The naive will not do anything and sooner than later will get burnt.
Assuming you trust your current modules and you can trust that they will not be altered, you can lock down the dependencies. But now monitor and updating a library when a bug or vulnerability is found in a modules become another burden.
Those actors that have the budget, patience and the motivation will always find a way in.
I sometimes feel quite sad about the real situation but there is not such a thing as perfect security.
That said some of the suggestions I see here will dramatically improve the situation with a relatively small effort. 2FA and reproducible builds for example.
One that comes closer is vcpkg [1], which is the Microsoft-run package manager for native C++ packages. It works by having the list of packages and recipes to build them (which it calls "ports") stored in a single repository. All requests to update them are submitted as pull requests and must be approved by Microsoft to enter the main repository.
I'm not necessarily saying whether this is a good or bad idea. Certainly it is a very different situation: only libraries that are already popular are considered, often the ports are submitted/maintained by different people than the library authors, and writing a port to build a library on multiple platforms may require significantly more work than just pointing at an existing GitHub repo. I just point to it as an alternative idea that has had some success.
[1] https://brew.sh/
Just require 2fa everywhere. We're way past the point where password-only is enough if you distribute software.
Package distribution platforms could also ensure that your package comes from a tagged/signed commit in a selected repo. Reproducible builds could help here too. Finally package signing itself and possibly WoT for authors. (Where either the author has to trust the dependencies or you have to explicitly trust all of them)
So, not trusting third parties is the only way and with that language level capability based security can help. Although this is pretty far from common programming languages where any function can access any file, environment variable, global variable, constant, socket, etc.
Rails 6.0, when generating a new app:
- installs 102 ruby gems (without being asked)
- installs yarn & 602 yarn dependencies (without being asked)
The modern programming industry is a joke. We call ourselves "engineers" without any certification or oaths of responsibility, and basically ignore security beyond user credentials at best.
Someone please tell me `yarn list | wc` showing 2,800 transient packages is incorrect.
[0]: https://gist.github.com/azah/c219844f95243cdfdb3b352ad3dee2f...
And it is worse that what you just found out. Did you think about all the software and dependencies that are installed just to get to the point where you can install Rails 6 (ex: Linux)?
What about your coworkers? Are you sure that you can trust all of them and nobody will not sneak anything in?
If you are too paranoid on who and what you can trust, you may end up tossing all your electronic devices and go living in a desert island.
However, this does not mean we should by default be installing heaps of packages upon generating new packages. This is practically begging for a security exploit, particularly the JS packages.
[0]: https://www.archive.ece.cmu.edu/~ganger/712.fall02/papers/p7...
Just doing some eyeballing:
- These look like the 62 gems in the production group: https://gist.github.com/gkemmey/6d6fcd381596b1b355d16e1e3120...
- Of those 62, how many are first party (by rails or other trusted vendors)? Looks like the vast majority...
- These look like the other 16 (dev / test groups): https://gist.github.com/gkemmey/6d6fcd381596b1b355d16e1e3120...
- On the JavaScript side, rails adds 5 top-level dependencies. 4 of those 5 have one external dependency between them: https://gist.github.com/gkemmey/6d6fcd381596b1b355d16e1e3120...
Of course, the fifth is `@rails/webpacker` which has `webpack`, `babel`, and friends as dependencies. And the node ecosystem is what it is, but I think `yarn list | wc` is going to double count shared dependencies, so 2800 is high.
TL;DR - I think new rails is about as minimal a footprint as possible...
Is there also a bundler-meta-audit the somewhere, so I can audit bundler-audit and it's dependencies? If not, maybe we should start a kickstarter for it?
This isn't going to go away, it's just a question of if/when the damage caused will get bad enough that people start to accept some of the tradeoffs that would be required to improve matters...
For commercially provided libraries that could be a contract specifying security requirements, with some specific measures of how to do that.
For Open source the only real option I can see is to curate your own package repositories and get a level of review that you're comfortable with. Definitely fixing versions and insisting on review before upgrade would help.
The problem with automated scanning is that they can't really find backdoors or just generally insecure code, they can find known vulnerabilities. They could use static analysis to find insecure code, but my experience of SAST tooling is that it takes a lot of manual effort to tune, it's not a pure automated scan option.
That's not to say that automated scanning provides nothing, but that it has limitations.
Basically all apps using package repo's (i.e. all of them) are relying on massive piles of unaudited 3rd party code with usually no idea of provenance.
Didn't this _also_ require a commit to the relevant Git repo? Or is it possible to upload a tarball directly to Rubygems without it being backed by a git repo?
> The backdoor was wisely hidden in the 3.2.0.3 version that was only published to RubyGems and no source of the malicious version existed on the GitHub repository and allowed remote attackers to dynamically execute code on servers hosting the vulnerable versions.
I'd like to know how they audit their system and the threshold of saying it is adequately secure.
I hope others copy this. This is truly scary.