Making popular Ruby packages more secure
blog.rubygems.org
blog.rubygems.org
If the rubygems devs are looking for other highly effective wins against supply chain attacks: I think the next thing is deeper support for lockfiles. Although Ruby has Gemfile.lock, it's not a true lockfile in the same way that package managers in the javascript/go/python ecosystems are. Specifically, locking versions is optional, there's no locking by hash (Github issue: https://github.com/rubygems/rubygems/issues/3379), and there's no capability to lock local or source-only dependencies by hash. By comparison: go modules, pipenv, npm, yarn, nuget, composer, and gradle already support locking by hash.
It looks like maybe it's been in flight for a while? https://github.com/rubygems/rubygems.org/pull/2108
While 2FA is good, having a purpose limited JIT token for publishing packages is what will actually reduce risk. Otherwise, as it stands - PATs leaked from one project can be used across any of your other packages on all package managers.
> I regret that the MFA token for many gems such as this may end-up in 1Password or similar, shared, along side the other credentials, rather than on a separate device or similar.
"> I regret that the MFA token for many gems such as this may end-up in 1Password or similar, shared, along side the other credentials, rather than on a separate device or similar."
Emphasis mine. How does "the extremely valid "gem is owned by a team, and anyone may push" model" impact this in any way? Why would the MFA tokens need to be shared via 1Password if they are specific to an individual account?
Unless you're sharing the username/password for a master account between everyone with push access to the gem (which, I checked, Capistrano thankfully doesn't appear to be doing), there's no reason whatsover to share the MFA token, so it could happily exist on a separate device. And if you are sharing one username/password between everybody – don't do that. You don't need to do that to accomplish "the extremely valid "gem is owned by a team, and anyone may push" model". That's just a really stupid way to do anything.
GP seems to be thinking that everyone with push rights needs to share the same token, but that's simply incorrect.
Am I missing something here?
No, enabling MFA for the most popular packages won't end all security, but also your strategy of targeting subdependencies isn't very good, every dependency of a popular project will be more popular than its dependent parent.
Sure, the maintainer could still naively update the dependencies and pull up a bad one during an update of the Popular Gem. But that Popular Gem update would have to happen after an attack on the dependency, and before the breach was discovered (assuming it has any way of being discovered before release of the popular package).
Lots and lots of gems depend on Rails and / or ActiveSupport. There's probably a lot more "glue" gems that are widely used for stuff like HTTP clients. Beyond that though, your typical gem doesn't have an enormous amount of dependencies, and there's a pretty good chance that the dependencies of the top X gems are themselves in the list of top X gems.
More details in the RFC: https://github.com/rubygems/rfcs/blob/master/text/0007-mfa-r...
Naturally there are security/convenience tradeoffs however you do it. The important thing is that, unlike with passwords, you never send the secret over the wire.
[0] https://blog.1password.com/totp-and-1password/#totp-isnt-the...
1. Package source hacking. Say an attacker gets access to a package source's storage and inserts malware into popular packages. Now your project contains malware. Your package manager can detect tampering if the packages are signed.
2. Dependency confusion attacks. Say my project downloads packages from the public source as well as my company's private source. An attacker realizes my company has a private package named `private-foo` and uploads a malicious package with the same name to the public source. Now my projects contains malware as it occasionally downloads the malicious package instead of my company's private package. Your package manager can detect packages from an unexpected author if they are signed.
I can provide more examples if you'd like. None of these are hypothetical, all of them have happened already.
Just want to point out that bundler solves this problem (and many others). It pins gem versions in Gemfile.lock and it supports explicit source locations (like git repositories) for downloading gems.
There's a proposal for a new "one button" approach using sigstore[0].
Other ecosystems are also looking at sigstore too, and a lot of us are cooperating in the OpenSSF Securing Software Repos WG [1]. Package signing is a regular topic of discussion and there are various efforts underway.
Disclosure: I am involved with both of these.
> RubyGems has had the ability to cryptographically sign gems since version 0.8.11. This signing works by using the gem cert command to create a key pair, and then packaging signing data inside the gem itself. The gem install command optionally lets you set a security policy, and you can verify the signing key for a gem before you install it.
> However, this method of securing gems is not widely used. It requires a number of manual steps on the part of the developer, and there is no well-established chain of trust for gem signing keys. Discussion of new signing models such as X509 and OpenPGP is going on in the rubygems-trust wiki, the RubyGems-Developers list and in IRC. The goal is to improve (or replace) the signing system so that it is easy for authors and transparent for users.
I tried it years ago and it was such a pain that I stopped, and I've a high tolerance for this kind of thing. I also found problems with certificate chaining that I've forgotten about (intentionally and gladly). Basically, it was like a lot of security stuff over the years, half-baked, badly implemented, with a poor UI and hence, doesn't get used.