Skip to content

Add dependency hashes to Gemfile.lock #39

@Hayden-IO

Description

@Hayden-IO

Introduction

Lockfiles provide a snapshot of the exact versions of dependencies used to build a gem. Lockfiles allow developers to build a gem using the same dependencies as the maintainer used.

Some package managers use the lockfile to provide security assurances that the dependencies have not been tampered. For example, in addition to Python's Pipfile to specify dependencies, pipenv will generate a Pipfile.lock which includes SHA256 hashes of all dependencies. NPM supports dependency integrity using package-lock.json. Comparing dependency hashes on installation securely guarantees that a package will be built using the exact same dependencies as the maintainer specified.

Lockfiles with hashes mitigate various attacks:

  • An attacker in a compromised network delivers malicious dependencies
  • A repository of packages is compromised and packages are replaced with malicious instances
  • Local packages on a machine are replaced with malicious instances

With hashes in lockfiles, when bundle install tries to install a dependency for a gem, a malicious dependency will not match the hash of the dependency in the lockfile, and the install will not succeed.

Proposal

I propose that Gemfile.lock include the SHA256 hash of each dependency. SHA256 hashes will be included after each versioned dependency. An example Gemfile and Gemfile.lock (Note the example hashes are random):"

Gemfile:

# frozen_string_literal: true
source "https://rubygems.org"

gem "nokogiri", ">= 1.4.2"

Gemfile.lock:

GEM
  remote: https://rubygems.org/
  specs:
    mini_portile2 (2.1.0) (d1bc8d3ba4afc7e109612cb73acbdddac052c93025aa1f82942edabb7deb82a1)
    nokogiri (1.6.8) (dc460da4ad72c482231e28e688e01f2778a88ce31a08826899d54ef7183998b5)
      mini_portile2 (~> 2.1.0)
      pkg-config (~> 1.1.7)
    pkg-config (1.1.7) (8b97bca79750847558d488e2ea4de79903c9c71c9af27ecf1b3dff5dba2abdd9)

PLATFORMS
  ruby

DEPENDENCIES
  nokogiri (>= 1.4.2)

BUNDLED WITH
   1.12.5

Implementation details

Hashes will be parsed in the lockfile parser. Hashes should be compared to downloaded dependencies before installation, such as when checking specs compatibility. I'm not familiar with the codebase, so please let me know if there's a simpler way to verify hashes.

For backwards compatibility, hashes will need to be optional initially, as previously generated lockfiles will not contain them. When hashes are present, they should be enforced. Hash enforcement should be all-or-nothing - All dependencies must include hashes, since any dependency missing a hash becomes a target for compromise. In addition, a flag can be added to bundle, such as --hashes, to require that hashes are present in the lockfile. In a future version, Bundler could mandate that hashes are present in the lockfile, but this would require maintainers to release gems with updated lockfiles or users would need to use an older version of Bundler.

Next steps

After a discussion on this issue, I'd like to propose this as an RFC.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions