The case against using RubyGems.org in production

Using RubyGems.org in production can leave you vulnerable to hacks. The only real way to have total control over your gems is to review the code for treachery and host the gems yourself. I'll show you how.

A screed + a screencast showing you how to host your own gems

Let’s get this out of the way: gems are awesome, and RubyGems.org is a great service.

...But lately I’ve been feeling queasy every time I add a new gem to an app. The more I think about it, the more it seems that the way we use gems isn’t just flawed. It’s a disaster waiting to happen.

Social engineering FTW

A few days ago at RubyNation, Ben Smith gave a great talk called Hacking With Gems.

Not hacking on gems, but using gems as a way to hack...as an attack vector.

He performed a cool experiment.

If you were at the conference, you probably saw stacks of nicely printed cards next to the github stickers and other swag.

The card said one thing: gem install rubynation. And about 10% of attendees did.

gem_install_ruby_nation

What the gem didn't do

The gem did some useful things. But what it didn’t do was more interesting.

It didn’t:

  • Steal the RubyGems.org credentials from your gemcutter dotfile

  • Intercept plaintext passwords and store them in your rails /public directory

  • Add a secret SSH account to your system

But it could have. Ask Ben if you don’t believe me.

This should scare you

Let me just back up and say this again, so it will sink in.

About 25 people - COMPUTER PROGRAMMERS - were manipulated into running arbitrary code on their development machines. A few even ran it as root.

I don't mean to pick on these people. This is just the norm in the Ruby community.

Why did it happen?

People trust gems.

  • Because they usually work.

  • Because Rails is a gem.

  • Because well-known folks like Aaron Patterson, Steve Klabnik, and Yehuda Katz maintain them.

But it’s a problem when you start trusting people you don’t know.

It's a problem when you type gem install rubynation with no more hesitation than you’d type gem install rails.

And let’s be honest. Who hasn’t done this at least once? We’re lazy and gems are easy.

Rubygems.org isn't to blame

It just makes it extremely easy to do the wrong thing. To run untrusted code on your servers. To be uninformed about changes in code run on your servers.

That's why I'm suggesting that we all stop using it in production.

Solutions

Signatures aren't enough

Everybody should sign their gems. But signatures aren’t enough. A signature only verifies the identity of the publisher. It doesn’t tell you if they’re good, evil, or chaotic neutral.

Nobody's coming to the rescue

In a perfect world, we’d have a trusted organization that distributes versions of gems that are known to be good.

If that rubs you the wrong way, then think about how organizations like Debian do something similar for Linux. If that still rubs you the wrong way....well I’m honored that you’re reading my blog, Mr. Stallman.

Why do I say in a perfect world? Well, because the other alternatives are a ton of work, and I’d rather not do it.

...can one of you YC hopefuls get on this please?

The only real option: DIY

Unfortunately I have to live in this smelly old real world. The only real way to have total control over your gems is to.

  • Review the code for treachery

  • Host the gems yourself

Fortunately, hosting your own gems is easy. I'll show you how.

How to host your own gems

It's not magic

A gem “server” is just a bunch of flat files on the web. You can host them anywhere, even on S3 or dropbox.

Make a Rails app as a testbench

The only reason I'm using rails here is because it gives us a premade Gemfile to play with. This app does nothing.

`$ rails new myapp
$ cd myapp
`

Download the .gem files

This bundler command will download all of the .gem files referenced by Gemfile.lock and put them in /vendor/cache

`$ bundle package
$ mkdir /tmp/gem_server
$ mv vendor/cache/ /tmp/gem_server/gems
`

Generate the 'server' files

To take a directory of .gem files and make them ready for serving, you run gem generate_index.

`$ gem generate_index -d /tmp/gem_server/
`

Put it all online

Now I wouldn't recommend this in production, but...

`$ mv /tmp/gem_server /Users/snhorne/Dropbox/Public/
`

Edit your Gemfile and bundle update

Update the "source" line to point to your new host instead of rubygems

`# Gemfile

source 'https://dl.dropboxusercontent.com/u/12345/gem_server'
...
gem 'rails', '3.2.13'
`

Cool! It's pulling gems from my dropbox.

`$ bundle update
Fetching gem metadata from https://dl.dropboxusercontent.com/u/12345/gem_server/.
Fetching full source index from https://dl.dropboxusercontent.com/u/12345/gem_server/
Using rake (10.1.0)
Using i18n (0.6.1)
Using multi_json (1.7.7)
Using activesupport (3.2.13)
`

Bonus: Private gems can be protected with HTTP basic authentication

Just make your gemfile look like this:

`# Gemfile

source 'https://username:password@example.com/'
`

Alternatives

Does this approach not work for you? There are some free and commercial gem hosting solutions that give you a few more bells and whistles.

Geminabox is an open source application that eliminates a lot of the command line work.

Gemfury is a private gem hosting company. I've used them in the past to host some proprietary gems for a client. It was easy to set up and never had a problem.

What to do next:
  1. Try Honeybadger for FREE
    Honeybadger helps you find and fix errors before your users can even report them. Get set up in minutes and check monitoring off your to-do list.
    Start free trial
    Easy 5-minute setup — No credit card required
  2. Get the Honeybadger newsletter
    Each month we share news, best practices, and stories from the DevOps & monitoring community—exclusively for developers like you.
    author photo

    Starr Horne

    Starr Horne is a Rubyist and Chief JavaScripter at Honeybadger.io. When she's not neck-deep in other people's bugs, she enjoys making furniture with traditional hand-tools, reading history and brewing beer in her garage in Seattle.

    More articles by Starr Horne
    Stop wasting time manually checking logs for errors!

    Try the only application health monitoring tool that allows you to track application errors, uptime, and cron jobs in one simple platform.

    • Know when critical errors occur, and which customers are affected.
    • Respond instantly when your systems go down.
    • Improve the health of your systems over time.
    • Fix problems before your customers can report them!

    As developers ourselves, we hated wasting time tracking down errors—so we built the system we always wanted.

    Honeybadger tracks everything you need and nothing you don't, creating one simple solution to keep your application running and error free so you can do what you do best—release new code. Try it free and see for yourself.

    Start free trial
    Simple 5-minute setup — No credit card required

    Learn more

    "We've looked at a lot of error management systems. Honeybadger is head and shoulders above the rest and somehow gets better with every new release."
    — Michael Smith, Cofounder & CTO of YvesBlue

    Honeybadger is trusted by top companies like:

    “Everyone is in love with Honeybadger ... the UI is spot on.”
    Molly Struve, Sr. Site Reliability Engineer, Netflix
    Start free trial