LASSIC Media らしくメディア
アプリの依存パッケージ管理と脆弱性対応
LASSIC IT事業部|元請(プライムベンダー)としてシステム保守・運用を受託
この記事のポイント
- iOSはSwift Package ManagerやCocoaPods、AndroidはGradleの依存宣言・バージョンカタログで、サードパーティライブラリのバージョンを管理します。
- 既知の脆弱性はDependabotやOSV-Scannerなどのソフトウェア構成分析(SCA)ツールと脆弱性データベースの照合で検知する仕組みが標準です。
- 依存の固定・検知・更新・検証という運用サイクルを設計しておかないと、脆弱性の見落としや更新時の回帰不具合につながります。
目次
アプリの依存パッケージ管理と脆弱性対応とは
アプリの依存パッケージ管理とは、iOS・Androidアプリの開発で利用するサードパーティ製ライブラリ(外部が公開しているコード資産)について、どのバージョンを使用するかを固定し、変更履歴を追跡できる状態を維持することを指します。あわせて、利用中のライブラリに既知の脆弱性が新たに公表されていないかを継続的に検知し、必要な更新につなげる活動を脆弱性対応と呼びます。この2つはアプリのコード品質を土台から支える運用であり、開発の初期段階だけでなく、リリース後も継続する性質を持ちます。
ここで扱う依存パッケージ管理・脆弱性対応は、アプリが利用する外部ライブラリのバージョンと既知の脆弱性を対象にした論点です。ソフトウェア部品表を作成するSBOM(Software Bill of Materials)や、アプリ全体の設計・実装レベルの堅牢性を評価するセキュリティ診断(MASVSに基づく評価など)とは扱う範囲が異なります。SBOMは依存関係の一覧を成果物として可視化する取り組みであり、セキュリティ診断はアプリ固有のロジックや設定を人手・ツールで評価する取り組みです。本稿では、その手前にある「依存をどう固定し、どう脆弱性を検知し、どう更新するか」という運用の設計に絞って解説します。
アプリ開発では、通信処理・画像読み込み・UIコンポーネントなど多くの機能をサードパーティライブラリに依存する構成が一般的です。自社で開発したコードの品質を高めても、依存先のライブラリに脆弱性が存在すれば、アプリ全体のリスクとして顕在化します。依存パッケージ管理と脆弱性対応は、自社が直接書いていないコードに対しても責任を持つための仕組みだと捉えると、優先度の位置づけが明確になります。
iOSの依存管理(Swift Package Manager/CocoaPods)とバージョン固定
iOSアプリの依存管理では、Swift Package Manager(SwiftPM)とCocoaPodsという2つの仕組みが広く使われています。それぞれ設定ファイルの構造と、バージョンを固定する仕組みが異なります。
Swift Package ManagerはPackage.swiftとPackage.resolvedで管理する
Swift Package Managerは、Swiftのソースコード・バイナリ・リソースの配布とビルドを管理する公式のツールです*1。依存関係はPackage.swiftに記述し、.packageで参照先のリポジトリと許容するバージョン範囲を宣言します。この宣言をもとに解決された依存関係の実際のバージョンは、パッケージの最上位ディレクトリに生成されるPackage.resolvedファイルに記録される仕組みです*2。Package.resolvedが存在する場合、SwiftPMは最新の対象バージョンを探すのではなく、このファイルに記録された内容を使って依存関係を解決します*2。
依存関係を最新の対象バージョンに更新したい場合はswift package updateコマンドを実行します。このコマンドはすべての依存関係を許容範囲内の最新バージョンに更新し、Package.resolvedを合わせて更新する仕組みです*2。Package.resolvedをバージョン管理システムにコミットしておけば、チーム全体で同じバージョンの依存関係を使う状態を維持でき、逆に.gitignoreに含める運用も選択できます*2。法人のアプリ開発では、ビルドの再現性を優先し、Package.resolvedをリポジトリに含めてレビュー対象にする運用が実務上のポイントになります。
CocoaPodsはPodfileとPodfile.lockで管理する
CocoaPodsは、SwiftおよびObjective-C向けの依存関係管理ツールで、10万を超えるライブラリが登録され、300万を超えるアプリで利用されているツールです*3。依存するライブラリ(Pod)はPodfileに記述し、pod installコマンドで実際のバージョンを解決してインストールします*3。CocoaPodsは長年iOS開発の標準的な依存管理ツールとして使われてきた経緯があり、SwiftPM登場後も既存プロジェクトの資産として併存しているケースが少なくありません。
iOSアプリの外注においては、新規開発ではSwiftPM、既存の大規模プロジェクトの保守ではCocoaPodsが混在する、あるいは両方を併用する構成に出会う場面があります。どちらの仕組みを使っているかによって、バージョン固定ファイルの場所とレビュー対象が変わるため、発注時にはどちらの依存管理を採用しているか、固定ファイルをリポジトリで管理しているかを確認しておく必要があります。
Androidの依存管理(Gradle・バージョンカタログ)
Androidアプリの依存管理はGradleビルドシステムが担います。依存関係はモジュールごとのビルドスクリプトにimplementationなどの構成(configuration)で宣言する仕組みです*4。
バージョンカタログでバージョンを一元管理する
Android Studioでは、新規プロジェクト作成時にバージョンカタログ(Version Catalog)を使う方式が既定の依存関係管理方法になっています*4。バージョンカタログはgradle/libs.versions.tomlファイルに[versions]セクションでバージョン番号を、[libraries]および[plugins]セクションでライブラリとプラグインのエイリアスを定義し、各モジュールのビルドスクリプトからはlibs.androidx.coreのような形式で参照する仕組みです*4。複数モジュールにまたがるプロジェクトで同じライブラリの複数バージョンが混在する事態を避けやすくなる点が、この方式を採用する主な理由です。既存プロジェクトについても、バージョンカタログへの移行が案内されています*4。
依存関係の構成(configuration)で公開範囲が変わる
Gradleの依存関係構成には、コンパイルとパッケージングの両方に含まれるimplementation、依存関係を他モジュールに推移的に公開するapi、コンパイル時のみ使うcompileOnly、実行時のみ使うruntimeOnlyなどがあります*4。apiを多用すると、あるモジュールが使うライブラリの詳細が他のモジュールにまで波及し、依存関係全体の見通しが悪化しやすくなるため、公開が本当に必要な場合に限定する設計判断が推奨されます。
また、バージョン指定において3.+のような動的バージョン(レンジ指定)を使う書き方は、ビルドのたびに異なるバージョンが取得される可能性があり、予期しない変更を招く要因になるため避けるべきとされています*4。バージョンカタログで固定のバージョン番号を明示的に管理する運用が、この動的バージョンのリスクを避ける実務上の対策になります。
| 観点 | iOS(SwiftPM/CocoaPods) | Android(Gradle) |
|---|---|---|
| 依存宣言ファイル | Package.swift(SwiftPM)/Podfile(CocoaPods) | モジュールのbuild.gradle(.kts) |
| バージョン固定ファイル | Package.resolved(SwiftPM)/Podfile.lock(CocoaPods) | gradle/libs.versions.toml(バージョンカタログ) |
| バージョン一元管理の仕組み | パッケージごとの許容範囲指定が基本 | バージョンカタログでの一元定義が既定の推奨方法*4 |
| 更新コマンド | swift package update(SwiftPM)*2/pod update(CocoaPods) | カタログのバージョン番号を変更して再ビルド |
| 依存グラフでの脆弱性検知対応 | GitHubの依存グラフはPackage.resolvedを認識*5 | GitHubの依存グラフで自動依存関係送信に対応*5 |
SCAによる既知脆弱性の検知(Dependabot・OSV等)
依存パッケージを固定した後は、そのバージョンに既知の脆弱性が存在しないかを継続的に検知する仕組みが必要になります。この検知活動を担うのがSCA(Software Composition Analysis。ソフトウェア構成分析)で、利用中の依存関係の一覧と脆弱性データベースを突き合わせる方法が中心です。
脆弱性データベースが検知の土台になる
既知の脆弱性情報は、CVE(共通脆弱性識別子)を管理するNVD(National Vulnerability Database。米国国立標準技術研究所が運用する脆弱性管理データの標準ベースのリポジトリ)*6や、GitHubが審査したアドバイザリを集約するGitHub Advisory Database、Googleが主導するOSV(Open Source Vulnerabilities)といった複数のデータベースに登録されます。OSVは40を超えるエコシステムに対応し、統一された脆弱性スキーマでオープンソースパッケージのバージョンやコミットハッシュに正確に対応する形式で脆弱性を記述する取り組みです*7。SCAツールは、これらのデータベースの情報と自社アプリの依存関係一覧を照合し、該当する脆弱性を洗い出します。
DependabotはGitHub上で依存関係の脆弱性を通知する
GitHubのDependabotアラートは、GitHub Advisory Databaseに新しい脆弱性が登録されたとき、または依存グラフに変更があったときに生成される仕組みです*8。対応するパッケージエコシステムは依存グラフの対応状況に準じており、Swift Package Manager・Gradle・Mavenを含む複数のエコシステムが依存グラフでサポートされています*5。Dependabotはアラートの通知だけでなく、対応するバージョンへの更新を提案するプルリクエストを自動生成する機能も持ち、検知から修正提案までを一体で運用できる点が特徴です。
OSV-ScannerはCLIで依存関係をスキャンする
OSV-Scannerは、プロジェクトの依存関係に影響する既知の脆弱性を見つけるためのツールで、OSVデータベースに接続して依存パッケージと脆弱性の対応を確認します*9。CLIツールとしてターミナルやCI/CDパイプラインに組み込んで直接実行できるほか、Goアプリケーションに脆弱性スキャンのロジックを組み込むライブラリとしても利用できる構成です*9。GitHubのエコシステムに閉じず、CI環境に依存しない形でスキャンを実行したい場合の選択肢になります。
いずれのツールを使う場合も、スキャンした結果として脆弱性が検出された後、実際にアプリの利用箇所への影響があるかを判断し、優先度をつけて対応する運用フローが伴って初めて機能します。ツールを導入しただけでは、通知が埋もれてしまい対応が進まない状態に陥りやすい点に注意が必要です。
更新運用の設計(破壊的変更・回帰テスト・更新頻度)
脆弱性を検知できても、更新の運用が設計されていなければ対応は進みません。依存パッケージの更新には、機能追加やバグ修正だけでなく、既存のAPIが変更・削除される破壊的変更が伴う場合があるためです。
破壊的変更の混入を前提に更新範囲を分ける
依存関係の更新は、パッチバージョンの更新(軽微な修正)とメジャーバージョンの更新(破壊的変更を含み得る更新)とで、リスクの大きさが異なります。脆弱性対応としての更新は速やかに進める必要がある一方、メジャーバージョンの更新は既存コードの修正が必要になる場合があるため、緊急度の高い脆弱性修正と、計画的なメジャーバージョン更新とを分けて運用する設計が実務的です。バージョンカタログやPackage.resolvedのようにバージョンが一元的に記録されていれば、どのライブラリがどのバージョンかを更新前に正確に把握でき、影響範囲の見積もりがしやすくなります。
回帰テストなしの更新は新たなリスクを生む
依存パッケージを更新した後は、アプリの主要な機能が従来どおり動作するかを確認する回帰テストが欠かせません。特に通信処理や認証まわりのライブラリは、バージョン更新によって内部の挙動が変わり、既存の実装が想定と異なる形で動作する可能性があります。自動テストの範囲が狭いプロジェクトほど、依存更新のたびに手動確認の工数が膨らみやすいため、更新運用を軌道に乗せるには、更新対象となりやすい主要ライブラリの周辺だけでもテストで担保しておく判断が有効です。
更新頻度は脆弱性の深刻度とリリースサイクルで決める
依存関係の更新頻度は、定期的なメンテナンス更新(月次など)と、脆弱性発覚時の緊急更新の2つの軸で設計します。緊急更新の判断基準としては、検知した脆弱性が自社アプリの実際の利用箇所に影響するか、深刻度がどの程度かを確認したうえで、通常のリリースサイクルを待たずに対応するかを判断する運用が求められます。更新を先送りし続けると、次に着手する際にはバージョン差分が大きくなり、破壊的変更への対応コストがまとめて発生する状態に陥りやすくなります。
外注時に確認すべき実装範囲と引き継ぎの論点
アプリの依存パッケージ管理と脆弱性対応をアプリ開発会社に外注する場合、開発フェーズだけでなくリリース後の運用フェーズまで含めてどこまでを実装範囲とするかを事前に整理しておく必要があります。
内製に必要なもの
依存パッケージ管理と脆弱性対応を内製で回すには、iOS・Androidそれぞれの依存管理の仕組みを理解した実装者に加え、SCAツールが出す検知結果を評価し、優先度をつけて対応判断ができる担当者が必要です。検知そのものはツールで自動化できますが、検知結果を読み解き、自社アプリへの影響を判断する工程は人の判断が介在するため、単にツールを導入するだけでは運用が回らない点に留意が必要です。
発注先への確認
提案書や見積もりに「脆弱性対応を実施します」とだけ記載されている場合、具体的にどのSCAツールを使うのか、検知した脆弱性への対応をどの頻度・どの基準で行うのか、バージョン固定ファイル(Package.resolvedやlibs.versions.tomlなど)をリポジトリで管理しているかを確認する必要があります。回答の解像度が低い場合、実際には検知の仕組みだけを導入し、対応運用までは設計されていないケースが少なくありません。
契約明記
開発会社との契約が終了した後、別の会社や自社に運用を引き継ぐ可能性がある場合は、依存関係の一覧・バージョン固定ファイル・SCAツールの設定内容・過去に対応した脆弱性の記録を納品物に含めるよう契約段階で明記しておく必要があります。これらの資料がないまま引き継ぐと、後任の担当者は現在の依存関係の状態を1から棚卸しするところから作業を始めることになり、追加の調査コストが発生しかねません。運用フェーズの脆弱性対応を保守契約の範囲に含めるかどうかも、契約時に明確にしておく論点です。
まとめ:依存管理と脆弱性対応を機能させる3つの判断軸
本稿では、iOSのSwift Package Manager・CocoaPods、AndroidのGradleにおける依存パッケージ管理と、SCAによる既知脆弱性の検知・対応運用について整理しました。要点を3つに集約すると次の通りです。第一に、依存関係はプラットフォームごとに固定ファイル(Package.resolved、Podfile.lock、バージョンカタログ)の仕組みが異なるため、自社のプロジェクトがどの方式を採用しているかを正確に把握しておく必要があります。第二に、脆弱性の検知はDependabotやOSV-Scannerといったツールと脆弱性データベースの組み合わせで自動化できますが、検知結果を評価し対応判断を下す工程は人が担う前提で運用を設計する必要があります。第三に、更新には破壊的変更のリスクが伴うため、緊急度に応じた更新区分と回帰テストの仕組みをあらかじめ用意しておく姿勢が、長期的な運用品質を左右します。
よくある質問
依存パッケージ管理とSBOM作成は同じ取り組みですか。
目的が異なります。依存パッケージ管理はバージョンの固定と脆弱性の検知・対応という運用を指すのに対し、SBOM(Software Bill of Materials)は使用している依存関係の一覧を成果物として可視化する取り組みです。SBOMを作成するにも依存関係の正確な把握が前提になるため、両者は関連しますが、本稿で扱う論点はSBOM作成そのものではなく、依存の固定と脆弱性対応の運用に絞っています。
SwiftPMとCocoaPods、どちらを使うべきですか。
新規のiOSプロジェクトではSwift Package Managerが公式のツールとして案内されていますが、既存プロジェクトで長くCocoaPodsを使っている場合、移行コストと利用中のライブラリの対応状況を踏まえて判断する必要があります*1*3。どちらを使う場合も、バージョン固定ファイル(Package.resolvedまたはPodfile.lock)をリポジトリで管理し、更新履歴を追跡できる状態にしておくことが重要です。
Dependabotを導入すれば脆弱性対応は自動化できますか。
検知と修正プルリクエストの生成までは自動化できますが、そのプルリクエストを実際にマージするかどうかの判断は人が行う前提です*8。検知された脆弱性が自社アプリの利用箇所に実際に影響するか、更新によって既存機能に問題が生じないかを確認する工程は自動化の対象外であるため、検知後の対応フローをあわせて設計しておく必要があります。
Androidのバージョンカタログは既存プロジェクトにも導入できますか。
既存プロジェクトについても、バージョンカタログへの移行が案内されています*4。複数モジュールで依存関係のバージョンがばらばらに管理されている状態から、gradle/libs.versions.tomlに一元化することで、バージョンの不整合や動的バージョン指定によるリスクを減らせます。移行作業には既存のビルドスクリプトの書き換えが伴うため、計画的に進める必要があります。
依存パッケージの更新はどのくらいの頻度で行うべきですか。
定期的なメンテナンス更新と、脆弱性発覚時の緊急更新を分けて運用する設計が実務的です。緊急更新は検知した脆弱性の深刻度と自社アプリへの影響範囲を確認したうえで、通常のリリースサイクルを待たずに対応するかを判断します。更新を先送りし続けるとバージョン差分が大きくなり、破壊的変更への対応コストがまとめて発生しやすくなるため、一定の周期で更新を回す仕組みをあらかじめ用意しておくことが望ましいでしょう。
著者:テレリモ総研編集部 鈴木 亮佑
ご不明な点はお問い合わせフォームからもご連絡いただけます。
- *1 出典:Swift.org「Swift Package Manager」https://www.swift.org/documentation/package-manager/
- *2 出典:Swift Package Manager Documentation「Resolving and updating dependencies」https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/resolvingpackageversions/
- *3 出典:CocoaPods公式サイトhttps://cocoapods.org/
- *4 出典:Android Developers「Add build dependencies」https://developer.android.com/build/dependencies
- *5 出典:GitHub Docs「Dependency graph supported package ecosystems」https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/dependency-graph-supported-package-ecosystems
- *6 出典:NVD(National Vulnerability Database)https://nvd.nist.gov/
- *7 出典:OSV(Open Source Vulnerabilities)https://osv.dev/
- *8 出典:GitHub Docs「About Dependabot alerts」https://docs.github.com/en/code-security/dependabot/dependabot-alerts/about-dependabot-alerts
- *9 出典:OSV-Scanner(google/osv-scanner)https://google.github.io/osv-scanner/