本文へスキップ
株式会社オープンナレッジ
株式会社オープンナレッジ Open Knowledge Inc.
Software Supply Chain:SBOM & Cryptographic Lock Verification 執筆:株式会社オープンナレッジ 技術調査・編集室(監修:加藤 明生)

オープンソースのサプライチェーン攻撃(悪意あるパッケージ混入)をどう防ぐか? SBOM(ソフトウェア部品表)と暗号学的ロック検証

対象:経営者様・システム発注ご担当者様・医療機器や製造装置メーカー様・Web開発エンジニアの方 / 読了目安:約5分

1. 基本と全体像

この記事の要点と4つの章のご案内

身近なたとえで見る仕組み:お弁当の「原材料表示ラベル」がないと、リコール時に何が起きるか?に関するイメージ写真
身近なたとえで見る仕組み:お弁当の「原材料表示ラベル」がないと、リコール時に何が起きるか?
構造図解:「中身不明のブラックボックス納品」と「SBOM+暗号学的ロック検証」の違いに関するイメージ写真
構造図解:「中身不明のブラックボックス納品」と「SBOM+暗号学的ロック検証」の違い
オープンソースのサプライチェーン攻撃(悪意あるパッケージ混入)をどう防ぐか? SBOM(ソフトウェア部品表)と暗号学的ロック検証 の各章におけるテーマと要点一覧表
章構成 主なテーマ 要点と確認ポイント
1. 基本と全体像 身近なたとえで見る仕組み:お弁当の「原材料表示ラベル」がないと、リコール時に何が起きるか? 現代のWebサイトや業務ソフトの80%〜90%は、世界中の技術者が資料公開している「共通部品(オープンソースやWordPressプラグイン等)」を組み合わせて作られており、その部品の1つが乗っ取られると利用企業すべてに被害が波及します。
2. 現場での進め方と対策 構造図解:「中身不明のブラックボックス納品」と「SBOM+暗号学的ロック検証」の違い そこで経済産業省や欧米の規制当局が推進しているのが、食品の「原材料・アレルギー表示ラベル」と同じように、ソフトの中身の部品リストを明記する「SBOM(エスボム:ソフトウェア部品表)」です。
3. 関連する制度とルール 現場で陥りやすい落とし穴と回避策 安全なシステムを維持するには、「出所不明のプラグインを増やさない(最小依存)」「部品の指紋(SHA-256ハッシュ値)をロックして勝手な書き換えを防ぐ」「SBOMで危険な部品を0秒で検索できるようにする」の3点が不可欠です。
4. 詳しい技術仕様としくみ 理解を深める確認クイズ スーパーやコンビニでお弁当やお菓子を買うと、裏面に必ず「原材料名:うるち米(国産)、鶏肉、醤油、卵...」という表示ラベルが貼られています。もしある調味料メーカーの工場で異物混入が発覚したとき、この「原材料リスト」が正確に記録されていれば、「うちのお弁当にはその調味料が使われているか、いないか」をわずか数分で確認し、安全宣言や素早い回収を行うことができます。
第1章〜第4章では、実務チェックリスト・公的制度基準・詳しい技術仕様を確認できます。
この記事のポイント
  • 01. 現代のWebサイトや業務ソフトの80%〜90%は、世界中の技術者が資料公開している「共通部品(オープンソースやWordPressプラグイン等)」を組み合わせて作られており、その部品の1つが乗っ取られると利用企業すべてに被害が波及します。
  • 02. そこで経済産業省や欧米の規制当局が推進しているのが、食品の「原材料・アレルギー表示ラベル」と同じように、ソフトの中身の部品リストを明記する「SBOM(エスボム:ソフトウェア部品表)」です。
  • 03. 安全なシステムを維持するには、「出所不明のプラグインを増やさない(最小依存)」「部品の指紋(SHA-256ハッシュ値)をロックして勝手な書き換えを防ぐ」「SBOMで危険な部品を0秒で検索できるようにする」の3点が不可欠です。
第1章:仕組みと構造図解

01. 身近なたとえで見る仕組み:お弁当の「原材料表示ラベル」がないと、リコール時に何が起きるか?

スーパーやコンビニでお弁当やお菓子を買うと、裏面に必ず「原材料名:うるち米(国産)、鶏肉、醤油、卵...」という表示ラベルが貼られています。もしある調味料メーカーの工場で異物混入が発覚したとき、この「原材料リスト」が正確に記録されていれば、「うちのお弁当にはその調味料が使われているか、いないか」をわずか数分で確認し、安全宣言や素早い回収を行うことができます。

ところが、これまでのソフトウェアやWebサイトの世界では、この「原材料表示」がないまま納品されるのが当たり前でした。現代のシステム開発では、1から100まで全部手書きでプログラムを作ることはまずありません。カレンダー表示、PDF作成、画像圧縮、メール送信など、世界中の開発者が公開している「オープンソース(OSS)の部品」や「拡張プラグイン」を何百個も組み合わせて1つのシステムを作っています。

近年、攻撃者は企業のサーバーを直接攻撃する代わりに、「世界中で使われている便利な無料プログラム部品の開発者アカウントを乗っ取り、最新のアップデート版にこっそり裏口(バックドア)を混ぜる」という手口(オープンソース・サプライチェーン攻撃)を激化させています。このとき、自社システムの中に「どの部品の、どのバージョンが入っているか」を記録した一覧表――すなわち「SBOM(Software Bill of Materials:ソフトウェア部品表)」がなければ、自社が被害を受けているかどうかすら調べることができないのです。

悪意あるプログラム部品が紛れ込む「3つの代表的な手口」

手口 01(放置された無料プラグインの買収・乗っ取り):
WordPressの無料プラグインやブラウザ拡張機能を作った個人開発者が更新をやめた際、攻撃者が「私が引き継ぎます」と買い取り、次の自動更新で数十万サイトへ一斉に不正プログラムを配信します。

手口 02(タイポスクワッティング=1文字違いの偽部品):
有名な部品名(たとえば `requests`)にそっくりな1文字違いの名前(`reqeusts` など)でウイルス入りの偽部品を登録し、エンジニアの入力ミスを待ち構えます。

手口 03(孫請け・ひ孫請け部品の汚染):
自分が直接選んだ部品(親部品)は安全でも、その部品が裏側で呼び出している「孫部品・ひ孫部品」に弱点や不正コードが潜んでいるケースが全体の7割以上を占めます。

ソフトウェアの構成比率
約 80〜90% が外部部品

現代の一般的なWebアプリケーションや業務ソフトのコードベースのうち、約8〜9割はオープンソースライブラリおよび間接依存パッケージで構成されています。

脆弱性の潜伏箇所
75% 以上が「孫部品」

開発者が直接指定したライブラリではなく、そのライブラリが内部で読み込む「間接依存(Transitive Dependencies)」に脆弱性の大半が潜んでいます。

国のガイドライン整備
経産省 SBOM手引書

経済産業省は医療機器・自動車・重要インフラ・ソフトウェア開発向けに『SBOM導入に関する手引書』を策定し、サプライチェーン全体での部品表管理を推進しています。

02. 構造図解:「中身不明のブラックボックス納品」と「SBOM+暗号学的ロック検証」の違い

外部のプラグインやライブラリを無秩序に詰め込んだシステムと、当社のRust採用基盤のように「最小限の部品+暗号学的ハッシュ固定(Cargo.lock)+SBOM自動生成」で守られたシステムの違いを図で比較してみましょう。

危険な状態:数十個の無料プラグインや数百の孫部品を「部品表(SBOM)なし・検証なし」で放置 01 外部の孫部品が乗っ取られる 海外の無料プラグインやOSS部品に 悪意あるコードや深刻な脆弱性が混入 02 ハッシュ検証なしでそのまま取込 「最新バージョンを自動取得」する設定で 汚染された部品を本番環境へ取り込む 03 部品表がないため影響調査不能 ニュースで脆弱性が報じられても、 自社システムに入っているか判別不能 安全な設計:「最小限の厳選部品」+「暗号学的ロック(Cargo.lock)」+「SBOM自動台帳」 防御 01:不要なプラグインの排除 出所不明のCMSプラグインを排し、 静的生成(Astro)とRust標準機能へ集約 効果:攻撃される入り口自体を極小化 防御 02:SHA-256指紋による全体固定 全依存部品の暗号ハッシュ値を記録し、 1バイトでも書き換わればビルドを即時停止 効果:すり替え・改ざん部品の混入を阻止 防御 03:SBOM(部品表)の常時照合 国際標準(CycloneDX)の部品表を生成し 新しい脆弱性データベースと毎日自動照合 効果:新種の脆弱性も数秒で該当有無を特定
第2章:Practical Field Guide & Self-Check

03. 現場で陥りやすい落とし穴と回避策

自社でプログラムを書かない中小企業にとっても、「ホームページ制作会社に頼んだWebサイト」や「外注して作ってもらった業務システム」を通じてサプライチェーン攻撃の被害に遭うケースが増えています。発注者・管理者の立場で押さえておきたい3つのポイントを見ていきましょう。

WordPress等の「無料プラグイン30個詰め込みサイト」の放置

現場の実態:「5年前に制作会社に作ってもらったホームページに、海外製の無料プラグインが30個以上入っており、誰も管理していない」

回避策: Webサイト改ざん被害の最大の原因は、CMS本体ではなく「後から追加されたサードパーティ製プラグインの脆弱性や開発放棄」にあります。不要なプラグインは直ちに削除し、さらに根本的な対策として、データベースや動的プラグインを外部に露出させない「事前ビルド型の静的Webアーキテクチャ(Astro等)」へ移行することで、プラグイン経由の乗っ取りリスクを構造的にゼロにできます。

システム開発委託時に「ロックファイル」や「部品一覧(SBOM)」を受け取っていない

現場の実態:「外注先にシステムを作ってもらったが、中にどんなオープンソース部品が使われているか一覧表がなく、開発担当者が辞めた後に保守できなくなった」

回避策: 外部のシステム開発会社にWebシステムやアプリを発注・検収する際は、納品物としてソースコードだけでなく「使用しているオープンソース部品とバージョン・ライセンスの一覧表(SBOM:CycloneDXまたはSPDX形式、および `Cargo.lock` / `package-lock.json` 等のロックファイル)」を必ず含めてもらうよう契約書(仕様書)に明記しましょう。

社員のパソコンに入っている「野良ブラウザ拡張機能・無料フリーソフト」

現場の実態:「社員が『PDFを結合したい』『画面を翻訳したい』と、ネットで見つけた無料のChrome拡張機能やフリーソフトを勝手に入れている」

回避策: 便利な無料ブラウザ拡張機能が攻撃者に買収され、ブラウザに入力した銀行パスワードやクラウドのセッション情報を裏側で抜き取る事件が毎年発生しています。会社で安全性と開発元を確認した「許可済みソフト・拡張機能リスト(ホワイトリスト)」を定め、それ以外の出所不明な拡張機能はポリシーで追加できないように保護しましょう。

Interactive Self-Check:Software Supply Chain Hygiene

ソフトウェア部品(プラグイン・OSS・拡張機能)の安全管理 3項目チェックリスト

自社のWebサイトや業務システム、パソコン環境について、以下の3項目をクリックして点検してみましょう。

現在 0 / 3 項目を確認済みです。クリックして自社のソフトウェア部品管理を点検してみましょう。 Web・システム部品診断へ →

04. 理解を深める確認クイズ

質問:経済産業省や国際的なセキュリティ基準で導入が進められている「SBOM(エスボム:ソフトウェア部品表)」を整備する最大のメリットはどれでしょうか?

選択肢 A:パソコンの画面デザインやフォントが自動的にきれいになる 解説を見る ↓

SBOMは画面デザインを変えるものではありません。
システム内部で使われているプログラム部品(ライブラリやモジュール)の種類・バージョン・提供元を正確に記録するための台帳です。

選択肢 B:世の中で特定のオープンソース部品に危険な弱点が見つかった際、自社システムにその部品が含まれているかを即座に特定して対処できる 解説を見る ↓

正解です。これがSBOM(ソフトウェア部品表)の最大の役割です。
食品の原材料表示やトレーサビリティと同じように、部品リストが明確になっていれば、緊急の脆弱性情報が発表されたその日のうちに影響有無を判断し、ピンポイントで安全に更新できます。

選択肢 C:どんなに怪しい無料プラグインを何百個入れても、一生アップデートしなくて済むようになる 解説を見る ↓

不要な部品を増やせば、それだけ管理とリスクが増大します。
そもそも怪しい外部部品を使わない「最小依存の設計」と、SBOMによる継続的な点検を組み合わせることが大切です。

関連コラム・豆知識

自動車産業の「部品番号管理」と食品衛生の「トレーサビリティ」がITに合流した理由

1台の自動車は約3万点の部品から作られていますが、自動車メーカーは「どの車体に、どの工場の、どのロットのボルトやセンサーが使われたか」を100%記録しています。だからこそ、万が一特定の部品に不具合が見つかっても、対象となる車体番号だけを正確に割り出して公開修理(リコール)を行えます。また、食品衛生(HACCP)の世界でも、原材料の仕入れ元から出荷先までの記録(トレーサビリティ)は命を守る基本です。これまで「目に見えないから」と曖昧にされがちだったソフトウェアの世界にも、製造業や食品衛生と同じレベルの誠実な品質管理を持ち込んだものが「SBOM」なのです。

自社Webサイトや業務システムの「プラグイン・部品リスク」を診断しませんか?

レガシーCMSからの安全な移行・SBOM整備に関する個別相談・設定確認

無料システム診断を申し込む →
場面別の実務確認ポイント
経営者・Webサイトオーナーの方へ

なぜ「制作会社に作ってもらったホームページの無料プラグイン」からある日突然ウイルスがばら撒かれるのか、食品の原材料表示のたとえ話で基本構造として整理しています。

製造・医療機器・調達ご担当者の方へ

経済産業省の「SBOM導入手引書」や欧米輸出規制(CRA等)で取引先から部品表(SBOM)の提出を求められた際の実務対応と発注時の確認事項を「第2章」にまとめています。

ソフトウェア・ビルド基盤技術者の方へ

Dependency Confusion / Typosquatting の攻撃構造、`Cargo.lock` のSHA-256マークル木検証、CycloneDX v1.6仕様、およびRust 2024による依存グラフ監査器を「第3章」で詳解します。

技術仕様・実装解説(CYCLONEDX v1.6 SBOM & CARGO.LOCK DAG VERIFICATION) 4. 詳しい技術仕様としくみ
Rust 2024(Deterministic Reproducible Builds)

Dependency Confusion / Typosquatting の有向非巡回グラフ(DAG)汚染モデル、`Cargo.lock` v4 SHA-256 ダイジェスト検証、および CycloneDX v1.6 準拠の Rust 2024 ビルド監査器

本モノグラフでは、パッケージマネージャにおける名前空間優先度逆転(Dependency Confusion)、編集距離 d_L ≤ 2 を狙う Typosquatting、およびビルドスクリプト(`build.rs` / `postinstall`)任意コード実行の攻撃ベクトルを分解する。さらに、有向非巡回グラフ G=(V, E) 上の推移的閉包に対する暗号学的ハッシュピンニング(`cargo build --locked`)と、Rust 2024 による依存関係ポリシー・レーベンシュタイン距離監査器の実装を提示する。

SBOM Standard
OWASP CycloneDX v1.6 / SPDX 3.0
Lockfile Integrity
Cargo.lock v4 SHA-256 Tree Pinning
Build Isolation
--locked --offline Vendored Source
Attestation Level
SLSA Build L3 Provenance
1. 設計仕様・数理モデル(Transitive Dependency Graph Contamination & Cryptographic Lockfile Pinning)

1. 推移的依存グラフ G=(V, E) における攻撃表面の指数的膨張:
ソフトウェアプロジェクトの依存関係を有向非巡回グラフ(DAG)G = (V, E) としてモデル化する。ルートアプリケーション v_0 ∈ V から到達可能なすべての直接・間接パッケージ集合を推移的閉包 T(v_0) = { u ∈ V | v_0 →^* u } とするとき、ビルド時または実行時にシステム全体が侵害される確率 P_compromise(v_0) は、各ノード u ∈ T(v_0) の侵害確率 p(u) に対して次式の論理和(OR結合)となる: P_compromise(v_0) = 1 - ∏_u ∈ T(v_0) (1 - p(u)) 特に、パッケージ展開時に任意のシェルコマンドやコンパイル時マクロ(`postinstall`, `build.rs`, `proc-macro`)がホスト権限で実行される環境では、深さ d ≥ 4 の末端パッケージ1個の侵害がルートシステム全体の全体掌握(RCE / CIシークレット窃取)と等価になる。

2. SemVer 浮動範囲指定(`^` / `~`)の危険性と `Cargo.lock` SHA-256 決定論的固定:
マニフェストファイル上で `version = "^1.4.0"` のような浮動範囲(Floating Range)のみを指定し、ロックファイルを無視してビルドを実行すると、パッケージレジストリ上でマイナーバージョン `1.4.99` が悪意あるメンテナにより公開された瞬間に自動追従して汚染される。これを防ぐため、すべてのパッケージ (name_i, ver_i, source_i) とその展開アーカイブの SHA-256 ダイジェスト h_i = SHA256(crate_i) を記録したロックファイルから全体のマークルルート相当ダイジェスト H_tree を構成する: H_tree = SHA256( \bigoplus_i=1^|T(v_0)| ( canonical(name_i, ver_i, source_i) ∥ h_i ) ) CI/CD パイプラインでは必ず `cargo build --locked --offline`(および `cargo vendor` によるソースコード全体検証)を強制し、未承認の1ビットの変更もコンパイル前に拒絶する。

3. Dependency Confusion と Typosquatting(レーベンシュタイン距離 d_L = 1)の静的検知:
社内プライベートパッケージ名 s_priv と同名の高バージョンパッケージがパブリックレジストリに登録される Dependency Confusion は、レジストリスコープの明示バインディング(`registry = "internal-mirror"`)によって遮断する。また、主要クレート集合 C_trusted に対してレーベンシュタイン編集距離 0 < d_L(name, c) ≤ 1 となる新規パッケージ追加をCIゲートで自動警告・ブロックする。

2. パラメータ・構成仕様(Supply Chain Threat Vectors & Deterministic Build Controls)
Supply Chain Vector Exploit Mechanism CycloneDX v1.6 Field Rust / CI Defense Control
Floating SemVer Hijack Compromised maintainer pushes malicious patch version `components[].hashes[SHA-256]` `cargo build --locked` + SHA-256 mismatch abort
Dependency Confusion Public registry shadows internal package name `components[].purl` & ` publisher` Explicit `.cargo/config.toml` source replacement
Typosquatting Package Lookalike name (`serde_jsonn`, `toki0`) `components[].name` Levenshtein check Edit-distance d_L = 1 pre-commit gate + `cargo vet`
Malicious `build.rs` RCE Network exfiltration of CI env vars during compile `formulation[].tasks` sandbox policy Network-isolated build container (`--offline`)
3. 実装コード・設定仕様(Executable Specification (crates/ok-sbom-auditor/src/lockfile_verifier.rs)) Rust 2024(Lockfile SHA-256 Pinning & Typosquatting Levenshtein Auditor)
#![forbid(unsafe_code)]

#[derive(Debug, Clone)]
pub struct SbomComponent {
    pub name: String,
    pub version: String,
    pub registry_url: String,
    pub expected_sha256: [u8; 32],
    pub actual_archive_sha256: [u8; 32],
    pub is_internal_namespace: bool,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SupplyChainAlert {
    Sha256DigestMismatch { package: String, version: String },
    DependencyConfusionRisk { package: String, registry: String },
    SuspectedTyposquatting { package: String, similar_to: String },
}

/// Computes bounded Levenshtein edit distance between two ASCII package names.
pub fn levenshtein_ascii(a: &str, b: &str) -> usize {
    let a_bytes = a.as_bytes();
    let b_bytes = b.as_bytes();
    let m = a_bytes.len();
    let n = b_bytes.len();
    let mut prev: Vec<usize> = (0..=n).collect();
    let mut curr = vec![0usize; n + 1];

    for i in 1..=m {
        curr[0] = i;
        for j in 1..=n {
            let cost = usize::from(a_bytes[i - 1] != b_bytes[j - 1]);
            let del = prev[j] + 1;
            let ins = curr[j - 1] + 1;
            let sub = prev[j - 1] + cost;
            curr[j] = del.min(ins).min(sub);
        }
        std::mem::swap(&mut prev, &mut curr);
    }
    prev[n]
}

/// Verifies all components in a locked dependency graph against hash integrity,
/// namespace pinning, and typosquatting distance against canonical packages.
pub fn verify_sbom_lock_graph(
    components: &[SbomComponent],
    canonical_popular_crates: &[&str],
    trusted_internal_registry: &str,
) -> Vec<SupplyChainAlert> {
    let mut alerts = Vec::new();

    for comp in components {
        // 1. Cryptographic SHA-256 lockfile verification
        let mut diff = 0u8;
        for i in 0..32 {
            diff |= comp.expected_sha256[i] ^ comp.actual_archive_sha256[i];
        }
        if diff != 0 {
            alerts.push(SupplyChainAlert::Sha256DigestMismatch {
                package: comp.name.clone(),
                version: comp.version.clone(),
            });
        }

        // 2. Dependency Confusion guard: internal packages must never resolve from public registries
        if comp.is_internal_namespace && comp.registry_url != trusted_internal_registry {
            alerts.push(SupplyChainAlert::DependencyConfusionRisk {
                package: comp.name.clone(),
                registry: comp.registry_url.clone(),
            });
        }

        // 3. Typosquatting guard: flag distance-1 lookalikes of canonical crates
        if !comp.is_internal_namespace {
            for &trusted in canonical_popular_crates {
                if comp.name != trusted && levenshtein_ascii(&comp.name, trusted) == 1 {
                    alerts.push(SupplyChainAlert::SuspectedTyposquatting {
                        package: comp.name.clone(),
                        similar_to: trusted.to_string(),
                    });
                }
            }
        }
    }

    alerts
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn catches_typosquat_and_hash_tampering() {
        let popular = ["serde", "tokio", "axum", "sqlx"];
        let components = vec![SbomComponent {
            name: "serd".to_string(),
            version: "1.0.0".to_string(),
            registry_url: "https://crates.io".to_string(),
            expected_sha256: [0x11; 32],
            actual_archive_sha256: [0x22; 32],
            is_internal_namespace: false,
        }];
        let alerts = verify_sbom_lock_graph(&components, &popular, "https://cargo.internal");
        assert_eq!(alerts.len(), 2);
    }
}
検証環境・運用について: 当社が開発するすべてのシステムは、`Cargo.lock` による暗号学的ハッシュ固定と自動脆弱性監査(`cargo audit` / CycloneDX SBOM)を標準適用しています。
SBOM作成・サプライチェーン監査のご相談
ご質問・公的制度の活用に関するお問い合わせ窓口

掲載資料に関するご質問・公的制度活用のご案内

本ページの図解や解説内容に関するご質問、経済産業省「SCS評価制度」やIPA「SECURITY ACTION・サイバーセキュリティお助け隊サービス」等の公的制度の確認方法について、落ち着いた参考窓口としてご案内しております。売り込みや営業連絡は一切行いませんので、社内勉強会やご家庭での確認資料としてご自由にご活用ください。

図解・ビジュアルの拡大表示

図表内のテキストもそのまま選択・検索可能です(ベクターSVG描画) 枠外クリックまたは ESC キーで閉じます