サプライチェーン攻撃とは、アプリ本体を直接狙うのではなく、依存ライブラリ、配布経路、ビルド環境、公開アカウントなど“作る過程”を経由して不正コードを混入させる攻撃です。npmの世界では、名前が似たパッケージを誤って入れさせる手口や、正規パッケージの更新・公開権限を乗っ取る手口、postinstall のようなインストール時スクリプトを悪用する手口が問題になります。大事なのは「依存は便利だから安全」と思わず、lockfile、差分レビュー、承認、CI検知、初動手順まで含めて、依存汚染を前提に運用を組むことです。

1. サプライチェーン攻撃とは
1-1. 直接攻撃と何が違うか(依存・配布経路が狙われる)
サプライチェーン攻撃は、自社アプリそのものを直接破るのではなく、その周辺にある依存・配布・更新経路を経由して入り込む攻撃です。アプリ本体のソースが堅くても、取り込んだ部品やその配布ルートが弱いと、そこが入口になります。
普段の開発では、npmパッケージを入れる、CIでビルドする、レジストリから依存を取得する、といった流れを当たり前に使います。サプライチェーン攻撃は、この「信頼しているつもりの流れ」に不正コードを乗せるのが特徴です。つまり、攻撃者は開発者の手元にある便利な仕組みを逆手に取って、正規っぽい形で侵入しようとします。
直接攻撃なら「このサーバに穴があるか」を見る発想になりやすいですが、サプライチェーン攻撃では「誰が何を取り込むか」「どこから落としてくるか」を見直す必要があります。npmやフロントエンド開発に触れ始めた段階では、まず「依存は外部入力の一種だ」と捉えるだけでも、防御の考え方がかなり変わります。
1-2. 何が起きるか(混入、乗っ取り、改ざん)
サプライチェーン攻撃で起きることは、大きく言うと不正コードの混入、配布アカウントの乗っ取り、更新経路の改ざんです。見た目は普通の依存追加やアップデートでも、中身が攻撃者にすり替わっていることがあります。
たとえば、悪意あるパッケージを誤って入れてしまえば、開発環境で秘密情報を抜かれたり、ビルド成果物に不正コードが紛れ込んだりします。正規パッケージでも、メンテナ権限が乗っ取られて悪性バージョンが公開されれば、通常の更新作業として取り込んでしまう可能性があります。つまり、信頼していた部品が急に危険物になるのが、サプライチェーン攻撃の怖さです。
被害の見え方もやっかいで、すぐ壊れるとは限りません。インストール時だけ情報を抜く、特定条件でだけ外部通信する、成果物に小さく混ざる、という形だと気づきにくいです。そのため、パッケージを入れる段階、更新する段階、CIで実行する段階ごとに「何が起きうるか」を分けて考える必要があります。
2. npmで起きやすい攻撃パターン
2-1. typosquatting(名前の似せ)
npmで分かりやすい攻撃パターンのひとつが、typosquattingです。これは、人気パッケージとよく似た名前のパッケージを公開し、タイプミスや見間違いで入れさせる手口です。
npmではパッケージ名を手で入力する場面が多く、名前が少し違うだけでも気づきにくいことがあります。たとえば、文字の並び替え、ハイフンの有無、複数形の違い、似た見た目の文字を使うなどで、正規パッケージに見せかけることができます。開発者が「よく知っている名前だから大丈夫」と思い込むと、そのまま取り込んでしまいやすいです。
対策としては、依存追加時に名前を手打ちで済ませず、公式ドキュメントや正規リポジトリから確認することが大切です。あわせて、PRレビューで「この新規依存は本当に意図した名前か」を見るだけでもかなり効果があります。チェックリストとしては、「初回追加時はnpmのページとGitHubのリンク先を確認する」「ダウンロード数や公開元をざっと見る」「レビューで新規依存を読み飛ばさない」の3つを最低ラインにすると回しやすいです。
2-2. 悪性アップデート/メンテナ乗っ取り
npmでは、新規追加よりも正規パッケージのアップデートに見せかけた混入のほうが気づきにくいことがあります。すでに使っている依存だからこそ、更新時の警戒が薄れやすいからです。
もしメンテナのアカウントが乗っ取られたり、公開権限が第三者に渡ったりすると、正規パッケージ名のまま悪性コードが配布される可能性があります。この場合、パッケージ名は正しいので、typosquattingより見抜きにくいです。さらに、semverの範囲指定が緩いと、意図しない版が自動的に入りやすくなります。
対策は、更新を「ただのメンテ」ではなくレビュー対象として扱うことです。特にメジャー更新だけでなく、普段見逃しやすいマイナー・パッチ更新でも、lockfile差分とリリースノートを確認する運用が役立ちます。実務向けのチェックとしては、「自動更新でもlockfile差分をレビューする」「重要依存は更新理由をPRに書く」「急な公開元変更や不自然な更新頻度を気にする」を置いておくと、違和感に気づきやすくなります。
2-3. postinstall悪用の考え方
npmで特に危険なのが、インストール時スクリプトの悪用です。代表的なのが postinstall で、依存を入れた瞬間に任意の処理を動かせるため、攻撃者にとって都合のよい実行ポイントになります。
npmパッケージには、インストールやビルドに合わせてスクリプトを動かす仕組みがあります。便利な一方で、悪意あるパッケージがそこへ情報送信や不正実行を仕込むと、開発者の手元やCI上で勝手に動いてしまいます。ここがやっかいなのは、「依存を入れたつもりが、すでにコードを実行していた」という状態になることです。
対策としては、インストール時スクリプトを“普通のこと”として無警戒に受け入れないことです。たとえば、CIで --ignore-scripts を検討できる場面があるか、信頼境界の外ではスクリプト実行を抑えられないかを見る価値があります。最低限のチェックとして、「新規依存のscripts欄を見る」「CIトークンや秘密情報がインストール工程で不要に露出していないか確認する」「インストール時通信を不自然に許しすぎない」を習慣にすると、被害を小さくしやすいです。
3. まず守る最低ライン(今日からできる)
3-1. lockfile運用と差分レビュー
npmの依存管理でまず守るべき最低ラインは、lockfileを正として扱い、差分をレビューすることです。これだけでも、意図しない依存変化に気づける確率がかなり上がります。
lockfileは、実際に解決された依存関係の具体的な状態を記録します。package.jsonだけだと範囲指定で曖昧なことがありますが、lockfileがあれば「何が実際に入ったか」を追いやすくなります。そのため、依存更新の実態を見るには、package.jsonだけでなくlockfile差分を確認することが重要です。
レビュー時は、「新しいパッケージが増えていないか」「意図しない深い依存が大量に変わっていないか」「関係ない更新が混ざっていないか」を見るのがおすすめです。チーム運用としては、「依存更新PRではlockfile差分を見る」「アプリ変更と依存更新を同じPRに混ぜすぎない」「npm installよりnpm ciを基本にする」といったルールが効きます。
3-2. 依存の追加/更新ルール(承認と例外)
依存追加や更新は、“開発者が自由に入れてよいもの”ではなく、最低限の承認ルールを持つだけで事故率が下がります。厳格すぎる統制は続きませんが、無制限も危険です。
特に新規依存は、アプリへ新しい外部コードを持ち込む行為です。そのため、なぜ必要か、代替はないか、配布元は妥当か、メンテ状況はどうか、を短くでも確認する価値があります。更新についても、全部を手で精査するのは難しいですが、「重要依存」「ビルドツール」「認証・通信系」など、リスクの高いカテゴリは少し厳しめに見るとバランスが取りやすいです。
現実的なルールとしては、「新規依存はPRで理由を1行書く」「高権限の開発依存はレビューを必須にする」「緊急更新の例外ルートを決めておく」といった形が回しやすいです。ポイントは、ルールを増やすことではなく、“危ない変更に気づくタイミング”をチームの中へ作ることです。
4. 事故を小さくする運用(検知と隔離)
4-1. CIでの検知(スキャン、ポリシー)
依存汚染を完全に防ぐのは難しいので、CIで早めに気づく仕組みを置くことが重要です。ここではスキャンとポリシーが土台になります。
CIでは、依存の脆弱性スキャン、ライセンス確認、lockfile差分の監視、不要なスクリプト実行の制限などを入れやすいです。すべてを厳しく止める必要はありませんが、「重大度が高いものは失敗にする」「新規依存追加時は注意喚起する」といった段階的な運用にすると現場へ乗せやすいです。検知は万能ではないものの、“人が気づけない変化を拾う”役割としてかなり有効です。
実務では、「CIで何を止めて、何を警告にするか」を決めておくと混乱しにくいです。チェックリストとしては、「lockfileが更新されたら検知する」「重大脆弱性をfail条件にする」「ビルド時の不要な権限を減らす」「トークンをCIへ過剰に置かない」を最低ラインにすると始めやすいです。
4-2. 漏えい時の初動(失効、ロールバック)
サプライチェーン事故では、“防ぐ”だけでなく“起きた後に素早く止める”ことも大切です。初動が遅いと、被害範囲が広がりやすくなります。
たとえば悪性パッケージを取り込んだ、またはCIトークンが漏れた疑いがある場合は、まず認証情報の失効、影響ビルドの特定、該当バージョンのロールバックや配布停止を考える必要があります。ここで「誰が何を止めるか」が決まっていないと、技術的に対処できても判断が遅れます。事故時は、原因究明より先に封じ込めを優先することが多いです。
最低限の初動ルールとしては、「npm token / CI token / クラウド鍵の失効手順を持つ」「最後の安全なlockfileへ戻せる状態を保つ」「問題の依存を含む成果物を一覧化できるようにする」が有効です。完璧なインシデント対応手順がなくても、この3つがあるだけで初動の質はかなり変わります。
5. SBOMとどう繋がるか(使いどころ)
5-1. 影響調査が速くなる理由
SBOMは、サプライチェーン攻撃そのものを防ぐ道具ではありませんが、影響調査を速くするためにはかなり有効です。特に、どの成果物にどの依存が入っていたかを追う場面で価値が出ます。
たとえば、あるnpmパッケージやその特定バージョンに問題が見つかったとき、SBOMがあれば「どのアプリ」「どのビルド」「どのコンテナ」に含まれているかをたどりやすくなります。lockfileだけでも調べられますが、成果物単位で整理されたSBOMがあると、配布済みのものまで含めて追跡しやすくなります。つまり、SBOMは影響範囲を探す時間を短くしてくれます。
実務では、「脆弱性アラートを見た担当者が、どこを見ればよいか分かる」ことが大切です。その意味で、SBOMはセキュリティチーム専用の文書というより、依存事故時の調査台帳として役立ちます。サプライチェーン攻撃対策では、予防だけでなく追跡可能性も大事なので、SBOMはその後半を支える位置づけです。
5-2. “SBOMがあっても防げない範囲”の線引き
一方で、SBOMがあれば攻撃を防げるわけではありません。ここを誤解すると、「SBOMを出したから安心」という危険な状態になりやすいです。
SBOMは、何が入っているかを記録し、後から確認しやすくするものです。しかし、悪性パッケージの初回導入そのものを止める、インストール時スクリプトの不正実行を無効化する、漏えいしたトークンの悪用を防ぐ、といった役割は直接は持ちません。つまり、SBOMは可視化と追跡には強いですが、予防と実行制御は別の運用が必要です。
現場では、「SBOM=守りの全部」ではなく、「lockfile管理、承認、CI検知、権限最小化と組み合わせるもの」と線引きしておくと整理しやすいです。SBOMは重要ですが、あくまで運用全体の一部です。この線引きができていると、期待しすぎず、でもちゃんと使える位置づけで運用しやすくなります。
6. まとめ
サプライチェーン攻撃は、アプリ本体の脆弱性ではなく、依存・配布・更新の流れを通じて侵入する攻撃です。npmでは、typosquatting、悪性アップデート、メンテナ乗っ取り、postinstall 悪用のように、「いつもの依存管理」に見える形で問題が入り込みます。
まず守る最低ラインは、lockfile運用、差分レビュー、依存追加の承認、CIでの検知です。さらに、事故が起きたときの初動として、トークン失効、ロールバック、影響成果物の特定まで考えておくと、被害を小さくしやすくなります。ここで大事なのは、便利さを捨てることではなく、「依存は信頼境界の外から来る」と理解して扱うことです。
SBOMは、こうした運用の中で影響調査を速くするために役立ちますが、単独で防御を完成させるものではありません。lockfile、最小権限、差分レビュー、CIポリシー、初動手順と組み合わせてはじめて効果が出ます。依存が危ないと言われて終わるのではなく、今日から回せるルールへ落とし込めるかが、実務では一番重要です。
7. 参考リンク
- npm Documentation
https://docs.npmjs.com/ - Node.js Security Working Group(関連情報の起点として)
https://github.com/nodejs/security-wg - OpenSSF(サプライチェーンセキュリティ関連)
https://openssf.org/ - OWASP Software Supply Chain Security Guidance(関連ガイダンス)
https://owasp.org/www-project-software-supply-chain-security/