Goの依存関係管理——URLで識別し、VCSから直接取得

筆者はGoを10年近く書いてきた後、直近の職場でRubyに触れる機会を得て、両言語の依存関係管理の違いを実感したといいます。(出典)Goでは依存関係を github.com/user/pkg のようなURLで識別し、指定したタグやコミットをGitなどのVCSから直接取得します。

go.mod ファイルが依存関係の仕様と「ロックファイル」を兼ね、直接・間接を含む依存関係ツリー全体を記録します。改ざん防止のため、全ファイルのハッシュが sum.golang.org で既知のハッシュと照合される仕組みもあります。

依存関係はURLで識別され、コードはVCSから直接取得される——直接・間接を問わずすべての依存関係について。

監査も容易だと筆者は言います。git log -p old..new でバージョン間の差分となるコミットをすべて読み、怪しいコードがないか確認するだけで済むためです。

「パッケージ公開」という手順に潜む攻撃の急所

一方Rubyでは、ソースコードを .gem アーカイブにまとめて rubygems.org に公開する「パッケージ公開」という手順を踏みます。公開されたアーカイブの中身が実際のソースリポジトリと一致する保証はありません。npmやPyPIなど、多くのパッケージシステムも同様の仕組みです。

観点 Go(VCSから直接取得) Ruby等(パッケージ公開を経由)
依存関係の実体 Gitのタグ・コミットそのもの .gem 等のアーカイブ(ソースと一致する保証なし)
改ざん検知 sum.golang.org でハッシュ照合 標準的な仕組みはない
差分監査 git log -p でコミット単位に確認可能 アーカイブを展開してdiffする必要があり、コミット履歴が失われる

筆者は、こうした監査は「できるにはできるが、決して簡単ではない」と評しています。

「攻撃者はソースリポジトリを狙わない」という指摘

筆者が見てきた「サイドチャネル攻撃」と呼ばれるものの多くは、実際にはより正確に言えば「パッケージ公開攻撃」だと述べています。RubyGems・npm・PyPI・.tar.gz のFTP配布など手段は様々ですが、共通するのは公開元のアカウントなどを乗っ取り、公開の手順に何かを注入するという点です。

ソースリポジトリそのものが侵害されることは稀だ。それはあまりに人目につきやすいからだ。攻撃を機能させるには、少なくとも多少は隠す必要がある。

実際にnpmで起きた侵害の多くは、npmアカウントへの不正アクセスと公開パッケージへの注入によるものだったといい、あるケースではソースリポジトリ自体にエクスプロイトコードが存在していたものの、それはバイナリのテストファイルの中に隠された不活性な状態で、改変された .tar.gz リリースの中でのみ有効化される仕組みだったと筆者は説明しています。

普段npmやPyPIのパッケージを気軽に追加してしまいがちな身としては、この記事を読んで、公開されたパッケージの中身をどこまで信頼していいのか改めて考えさせられました。