Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand gem security build/install instructions; add checksum #70

Merged
merged 7 commits into from
Nov 21, 2013
88 changes: 78 additions & 10 deletions security.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,40 +28,108 @@ 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 using
X509 or OpenPGP is going on in the [rubygems-trust
wiki](https://github.com/rubygems-trust/rubygems.org/wiki/_pages) and
of [manual steps on the part of the developer](#building_gems), 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](https://github.com/rubygems-trust/rubygems.org/wiki/_pages), the
[RubyGems-Developers list](https://groups.google.com/d/msg/rubygems-developers/lnnGTlfsuYo/TLDcJ2RPSDoJ) and
in [IRC](irc:https://chat.freenode.net/#rubygems-trust). The goal is to improve (or
replace) the signing system so that it is easy for authors and transparent for
users.

Using Gems
-------

* Install with a trust policy.
Install with a trust policy.
* `gem install gemname -P HighSecurity`: All dependent gems must be signed and verified.
* `gem install gemname -P MediumSecurity`: All signed dependent gems must be verified.
* `bundle --trust-policy MediumSecurity`: Same as above, except Bundler only recognizes
the long `--trust-policy` flag, not the short `-P`.
* Risks of being pwned, as described by [Benjamin Smith's Hacking with Gems talk](http:https://lanyrd.com/2013/rulu/scgxzr/)
* *Caveat*: Gem certificates are trusted globally, such that adding a cert.pem for one gem automatically trusts
all gems signed by that cert.

Verify the checksum, if available

gem fetch gemname -v version
ruby -rdigest/sha2 -e "puts Digest::SHA512.new.hexdigest(File.read('gemname-version.gem'))

Know the risks of being pwned, as described by [Benjamin Smith's Hacking with Gems talk](http:https://lanyrd.com/2013/rulu/scgxzr/)

Building Gems
-------

* Official: `gem cert`
### Sign with: `gem cert`

1) Create self-signed gem cert

cd ~/.ssh
gem cert --build [email protected]
chmod 600 gem-p*

- use the email address you specify in your gemspecs

2) Configure gemspec with cert

Add cert public key to your repository

cd /path/to/your/gem
mkdir certs
cp ~/.ssh/gem-public_cert.pem certs/yourhandle.pem
git add certs/yourhandle.pem

Add cert paths to your gemspec

s.cert_chain = ['certs/yourhandle.pem']
s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/

3) Add your own cert to your approved list, just like anyone else

gem cert --add certs/yourhandle.pem

4) Build gem and test that you can install it

gem build gemname.gemspec
gem install gemname-version.gem -P HighSecurity
# or -P MediumSecurity if your gem depends on unsigned gems

5) Example text for installation documentation

> MetricFu is cryptographically signed. To be sure the gem you install hasn't been tampered with:
>
> Add my public key (if you haven't already) as a trusted certificate
>
> `gem cert --add <(curl -Ls https://raw.github.com/metricfu/metric_fu/master/certs/bf4.pem)`
>
> `gem install metric_fu -P MediumSecurity`
>
> The MediumSecurity trust profile will verify signed gems, but allow the installation of unsigned dependencies.
>
> This is necessary because not all of MetricFu's dependencies are signed, so we cannot use HighSecurity.

-------

### Include checksum of released gems in your repository

* [How to cryptographically sign your RubyGem](http:https://www.benjaminfleischer.com/2013/11/08/how-to-sign-your-rubygem-cert/) - Step-by-step guide
require 'digest/sha2'
built_gem_path = 'pkg/gemname-version.gem'
checksum = Digest::SHA512.new.hexdigest(File.read(built_gem_path))
checksum_path = 'checksum/gemname-version.gem.sha512'
File.open(checksum_path, 'w' ) {|f| f.write(checksum) }
# add and commit 'checksum_path'

-------

* Alternative: [Rubygems OpenPGP signing](https://web.archive.org/web/20130914152133/http:https://www.rubygems-openpgp-ca.org/), [gem](https://github.com/grant-olson/rubygems-openpgp)
### Not Recommended: OpenPGP signing is [not recommended due to lack of support](http:https://www.rubygems-openpgp-ca.org/blog/nobody-cares-about-signed-gems.html).

* For example, see the [ruby-lint gem](https://github.com/YorickPeterse/ruby-lint/blob/0858d8f841/README.md#security)
For details, see discussion [with Grant Olson](https://github.com/grant-olson/rubygems-openpgp/issues/34#issuecomment-29016709) and
[Yorick Peterse](https://github.com/rubygems/guides/pull/70#issuecomment-29007487).

Credits
-------

Several sources were used for content for this guide:

* [How to cryptographically sign your RubyGem](http:https://www.benjaminfleischer.com/2013/11/08/how-to-sign-your-rubygem-cert/) - Step-by-step guide
* [Signing rubygems - Pasteable instructions](http:https://developer.zendesk.com/blog/2013/02/03/signing-gems/)
* [Twitter gem gemspec](https://github.com/sferik/twitter/blob/master/twitter.gemspec)
* [RubyGems Trust Model Overview](https://github.com/rubygems-trust/rubygems.org/wiki/Overview), [doc](http:https://goo.gl/ybFIO)
Expand Down