世界水準編第24章

SBOMとSLSA:サプライチェーンの世界標準

読む目安:約40分自分のアプリの「部品表」を出し、来歴を確かめる仕組みを知る

あなたのアプリは、あなたが書いた(AIが書いた)コードだけでできているわけではありません。何百という他人の部品(パッケージ)を組み合わせて動いています。経理が仕入先台帳と部品表を持つように、アプリにも部品表が要ります。それがSBOMです。この章では、SBOMの世界標準と、部品の「来歴」を保証するSLSAや署名の仕組みを読み、自分のアプリの部品表を実際に出します。

この章の学習目標

  • SBOMとは何かを経理の部品表・仕入先台帳にたとえて説明し、NTIAの最小要素とSPDX/CycloneDXという2つの形式の名前を言えるようになる
  • 自分のアプリのSBOMを生成し、直接依存と間接依存の数を数え、更新が止まっている部品を洗い出せるようになる
  • SLSAのレベルとSigstore/npm provenanceの役割を説明し、「来歴が確認できる部品」と「できない部品」を区別できるようになる

SBOM:ソフトウェアの部品表

SBOM(Software Bill of Materials、ソフトウェア部品表)は、CISAの定義では「ソフトウェアを構成する部品の、入れ子になった一覧。いわば原材料表示」です。製造業の部品表(BOM)と同じ言葉が使われているのは偶然ではありません。「この製品に、どの部品が、どの版で、どこから入っているか」を機械が読める形で持つ、という発想です。

経理に引き寄せるなら、仕入先台帳に近いものです。ある仕入先に問題が起きたとき、台帳があれば「どの製品に、その部品が入っているか」がすぐ分かります。台帳が無ければ、全製品を一つずつ調べることになります。広く使われている部品に重大な脆弱性が公表されたとき、「自社のどこにその部品が入っているか分からない」状態に陥る組織は少なくありません。SBOMは、その状態を無くすためのものです。

制度は米国が先行しています。2021年5月の大統領令14028が政府に納めるソフトウェアにSBOMを求め、同年7月12日に米国商務省NTIAが「SBOMの最小要素(The Minimum Elements For a Software Bill of Materials)」を公表しました。3つの区分に分かれます。

区分NTIA最小要素(2021年7月)経理で言えば
データ項目供給者名、部品名、部品の版、その他の一意な識別子、依存関係、SBOM作成者、作成日時(7項目)仕入先、品名、型番、品番、構成、作成者、作成日
自動化の支援自動生成できること、機械可読であること。形式はSPDX、CycloneDX、SWIDタグ会計システムから台帳をCSVで出せること
実務と手順頻度、深さ、既知の不明点、配布と受け渡し、アクセス制御、誤りの許容更新サイクル、どこまで細かく持つか、未確認の扱い、共有範囲

2025年8月22日には、CISAが「2025 Minimum Elements for a Software Bill of Materials」の草案を連邦官報で公表し、10月3日まで意見を募集しました。CISAの発表によれば、2021年版に「部品のハッシュ値」「ライセンス」「生成ツール名」「生成時の文脈」が追加されています。本稿執筆時点で確定版の公表は確認できていません。日本では、経済産業省が「ソフトウェア管理に向けたSBOMの導入に関する手引 ver 2.0」(2024年8月)を公開しています。

2つの形式:SPDXとCycloneDX

SBOMの形式は、実務上2つに集約されています。どちらも機械が読めるファイル(JSONなど)で、人が目で読むものではありません。

SPDX
Linux Foundationが主催する形式。2021年8月にISO/IEC 5962:2021として国際規格になりました。3.0は2024年4月に公開され、同年12月に修正版の3.0.1が出ています。ライセンス情報の記述から発展してきた経緯があります。
CycloneDX
OWASPが主催する形式。Ecma InternationalのTC54と共同で進められ、ECMA-424として標準化されています。SBOMだけでなく、脆弱性情報(VEX)なども同じ枠組みで扱えます。

どちらを使うかで悩む必要はありません。相手(取引先、監査、ツール)が指定する形式に合わせるだけです。

個人開発でのSBOM:もう持っている

あなたのリポジトリには、すでにSBOMの材料があります。Node.jsなら package-lock.json です。間接依存まで含めて「どのパッケージの、どの版を使っているか」を固定したファイルで、NTIAのデータ項目のうち部品名と版と依存関係を含んでいます。

Pythonの requirements.txt は事情が違います。版を == で固定して書くこともできますが、版を書かないことや、範囲(>= など)で書くことも許されており、間接依存が入っているとも限りません。pip freeze で書き出した一覧なら、その時点で入っているパッケージと版は固定されますが、「どれがどれに依存しているか」の関係は含まれません。そのままでは完全な部品表にならない、と覚えておいてください。

標準形式に変換する道具もあります。npmの npm sbom コマンドは、--sbom-format に cyclonedx か spdx を指定すると、依存関係をその形式で出力します。--sbom-type application でアプリケーションであることを示せます。npmの公式ドキュメントに載っている機能です。

ここで大切な区別が、直接依存と間接依存です。

直接依存
あなた(またはAI)が package.json に書いて入れたパッケージ。自分で選んだ仕入先。
間接依存
直接依存のパッケージが、さらに使っているパッケージ。仕入先の、そのまた仕入先。自分で選んでいないのに、アプリの中で動いている。

直接依存が十数個でも、間接依存を含めると数百を超えることは珍しくありません。論文で「サプライチェーンの不備」が73件(6.16%)あったのは、この「自分で選んでいない部品」の管理が抜けるからです。第12章で有効にしたDependabotは、この部品表を自動で読んで「脆弱性のある部品が入っている」と知らせる仕組みです。

SLSA:ビルドの来歴を保証する

SBOMは「何が入っているか」を答えます。しかし「その部品は、本当に名乗っている通りの出どころから、改ざんされずに来たのか」には答えません。それを扱うのがSLSA(Supply-chain Levels for Software Artifacts、「サルサ」と読みます)です。Linux Foundation傘下のOpenSSFが進める枠組みで、「改ざんを防ぎ、完全性を高め、パッケージと基盤を守るための基準と統制のチェックリスト」と自己定義しています。

中心にある概念が来歴(provenance)です。SLSAの定義では「どの主体が、どの手順で、どの入力から、その成果物を作ったか」を記した情報です。経理で言えば、納品物に添付される「製造元と製造工程の証明書」です。現在の承認済みの版はv1.2で、「Build(ビルド)」と「Source(ソース)」の2つのトラックがあります。

トラックレベル要旨(原典の要約)
BuildL0要件なし。SLSAが無い状態
L1来歴が存在する。どう作られたかが記されているが、偽造は容易
L2ホスト型のビルド基盤が来歴を生成し署名する。偽造には明示的な攻撃が要る
L3強化されたビルド基盤。偽造には脆弱性の悪用が要り、ビルド同士の干渉や署名鍵への接触を防ぐ
SourceL1ソースが最新のバージョン管理システムで管理されている
L2履歴が連続・不変で保持され、ソースの来歴証明が発行される
L3保護対象のブランチに、組織の技術的統制が強制されている
L4保護対象のブランチへの変更に、信頼できる2名のレビューが要る

Source L4の「2名のレビュー」は、経理の職務分掌そのものです。AIが書いた変更を自分だけで本番に入れている個人開発は、Source L1かL2の段階です。だからこそ「レビューを別のセッションや別のAIに通す」という第13章の原則が効きます。

署名と来歴の実装:Sigstoreとnpm provenance

SLSAの来歴を実際に作り、確かめる道具として、Sigstoreがあります。OpenSSF(Linux Foundation)が支える公共のサービスで、署名用のクライアント(cosign)、身元と結びついた短命の証明書を発行する認証局(Fulcio)、署名の記録を追記専用の公開台帳に残す透明性ログ(Rekor)で構成されます。長期の秘密鍵を自分で管理せずに済み、記録は登記簿のように公開されます。

npmはこれを「npm provenance(来歴)」として組み込んでいます。npmの公式ドキュメントによれば、GitHub ActionsやGitLab CI/CDのホスト型の実行環境から npm publish --provenance で公開すると、そのパッケージが「どのリポジトリの、どのコミットから、どの手順で作られたか」を示す来歴証明が、Sigstoreの公開サーバーで署名され、公開台帳に記録されます。利用者側は npm audit signatures で、インストール済みのパッケージのうち署名と来歴証明が検証できたものの数を確認できます。

ただし、npmのドキュメント自身が「来歴は、パッケージに悪意あるコードが無いことを保証するものではない」と明記しています。来歴が示すのは「名乗っている出どころから来た」ことだけです。印鑑証明が付いていても、その会社が架空取引をしていないことまでは証明されないのと同じです。

第16章との接続:slopsquattingと影響範囲

第16章で見たslopsquatting(AIが幻覚した存在しないパッケージ名を、攻撃者が先回りして登録する手口)は、第23章のATLASではAML.T0060「Publish Hallucinated Entities」、ATT&CKではT1195.001「Compromise Software Dependencies and Development Tools」に当たります。この手口への備えとして、SBOMは2つの役割を果たします。

  • 事前:SBOMを出して直接依存の一覧を目で見ると、「このパッケージ、自分は入れた覚えがない」「名前が似た別物ではないか」に気づけます。AIが提案したパッケージ名は、公式レジストリ(npmjs.com、pypi.org)で実在と公開日、週間ダウンロード数、来歴の有無を確かめてから入れます。
  • 事後:あるパッケージが悪意あるものだったと公表されたとき、SBOMがあれば「自分のアプリに入っているか、どの版か、何経由で入ったか」を数分で答えられます。無ければ、全ファイルを探すことになります。
AIへの頼み方(SBOMの読み解き)
このリポジトリの依存関係を、サプライチェーンの観点で整理してください。

1. 直接依存(package.json または requirements.txt に書かれているもの)の一覧を、「パッケージ名/版/用途(このアプリで何に使っているか)/最後にインストールした理由が分かるか」の表にしてください
2. 直接依存の数と、間接依存を含めた総数を、ロックファイル(package-lock.json など)から数えてください
3. 直接依存のうち、このアプリのコードから実際には使われていないもの(import や require が無いもの)を挙げてください
4. 名前が有名なパッケージと紛らわしいもの、公式レジストリでの確認が必要と思われるものがあれば、理由を添えて挙げてください
5. 修正やアンインストールはまだしないでください。報告だけお願いします

パッケージの実在や公開日、ダウンロード数は推測せず、「公式レジストリで確認が必要」と書いてください。

演習:自分のアプリのSBOMを出し、古い部品を洗い出す

所要時間:約35分
  1. リポジトリのフォルダで npm sbom --sbom-format cyclonedx --sbom-type application を実行し、出力をファイルに保存します(Pythonのプロジェクトなら、pip freeze で、入っているパッケージと版の一覧を書き出して保存します。依存関係のつながりまでは入らない点を点検ノートに書き添えます)。
  2. 上の定型文でAIに依存関係を整理させ、直接依存の数と総数を点検ノートに書きます。数の差が「自分で選んでいない部品」の数です。
  3. npm outdated を実行し、現在の版より新しい版が出ているパッケージを一覧にします。直接依存のうち、1年以上新しい版に追随していないものに印を付けます。
  4. AIが「使われていない」と報告した直接依存について、本当に使っていないかを自分で確かめ(検索で import を探す)、使っていなければ削除の候補にします。部品が少ないほど、管理する仕入先が少なくて済みます。
  5. npm audit signatures を実行し、署名と来歴証明が検証できたパッケージの数を記録します。来歴の無いパッケージが多くても、それ自体は異常ではありません。「来歴の有無を知っている」状態にすることが目的です。
  6. 第12章のDependabotの通知と照らし、未対応のものがあれば、第13章の手順で更新します。更新のあとは第10章・第11章の確認を再実行します。
  7. SBOMファイルの保存場所と作成日を点検ノートに書きます。大きな依存の追加や更新のたびに作り直します。
注意:SBOMの公開範囲と、他人のパッケージの扱い SBOMには「どの部品のどの版を使っているか」が書かれます。脆弱性が公表された部品を使っていれば、その事実も読み取れます。公開リポジトリには入れず、点検ノートと同じく手元に置いてください。また、紛らわしい名前のパッケージを見つけても、その公開者を特定したり、パッケージの中身を他人の環境で「試す」ことはしないでください。疑わしいものは、公式レジストリの報告窓口に通報するのが正しい対応です。

まとめ

  • SBOMはアプリの部品表。NTIAの最小要素(2021年7月)は供給者名・部品名・版・識別子・依存関係・作成者・作成日時の7項目。CISAは2025年8月にハッシュ値・ライセンス・生成ツール名・生成時の文脈を加える草案を公表。形式はSPDX(ISO/IEC 5962:2021)とCycloneDX(ECMA-424)。
  • package-lock.jsonはすでに原始的なSBOM(requirements.txtは書き方次第で版や間接依存が抜けるので、そのままでは不十分)。npm sbomで標準形式に変換できる。直接依存(自分で選んだ)と間接依存(自分で選んでいない)を区別し、使っていない部品を減らし、更新が止まった部品を洗い出す。
  • SLSA v1.2は来歴(誰が、どの手順で、どの入力から作ったか)を保証する枠組みで、BuildトラックL0〜L3とSourceトラックL1〜L4がある。Sigstoreとnpm provenanceが来歴に署名し公開台帳に残す。ただし来歴は「出どころ」の証明であって「安全」の証明ではない。SBOMがあれば、slopsquattingなどの事故時に影響範囲をすぐ特定できる。

出典