脆弱な依存パッケージを見つけて修正する

PythonBeginner
オンラインで実践に進む

はじめに

アプリケーションは、他のプロジェクトが作成したライブラリに依存しています。自分のプログラムが正常に動作しているように見えても、便利なライブラリに既知の弱点がある場合があります。この DeskLite チケットクライアントは、Python の HTTP ライブラリ Requests の、問題の影響を受けるバージョンを使っています。

このラボでは、固定されたオフラインのアドバイザリーを読み取り、クライアントが実際にインポートするパッケージを更新し、機能とバージョンの記録を合わせて確認します。独立した Python 環境、インストール用キャッシュ、2 件のアドバイザリーを含むコース用スナップショットは用意されています。パッケージ管理や Python プログラミングの経験は必要ありません。

クライアントを実行してパッケージを確認する

このステップでは、クライアントの現在の業務動作を確認し、インストールされている依存パッケージの場所を調べます。

依存関係とは、アプリケーションが利用するソフトウェアです。このクライアントは、HTTP リクエストを送るために requests を直接使います。Requests 自体も、その処理の一部に別のライブラリ urllib3 を使っています。この 2 番目の関係が推移的依存関係です。

cd /home/labex/project/desklite-dependencies

.venv/bin/python は、このプロジェクト用に用意された独立した Python 実行ファイルです。そのパッケージはシステムの Python とは別に管理されています。有効化コマンドやグローバルなインストールは不要です。Git のラボで提供されたプログラムを実行したときと同様に、提供されたクライアントを実行します。

.venv/bin/python app.py

タイトルが Printer offline の元のチケットが返るはずです。セキュリティ上の修正前でもプログラムは動作します。依存関係に既知の問題があっても、すべてのリクエストがすでに失敗するとは限りません。

pip は Python パッケージを管理します。-m pip は、同じ独立した Python にそのパッケージマネージャーを実行させます。show は何も変更せずにメタデータを読み取ります。

.venv/bin/python -m pip show requests urllib3

Name、Version、Location を探してください。Requests は 2.32.3、urllib3 は 2.2.2 で、パッケージの場所はこのプロジェクトの .venv 内にあるはずです。更新するのは、この環境であり、別の Python 環境ではありません。

オフラインのアドバイザリー検出結果を読み取る

このステップでは、スキャナーの検出結果と、対応が必要なパッケージのバージョンを関連付けます。

用意されている course-deps ランチャーは、2026-10-28 付の固定されたローカルスナップショットに対して OSV-Scanner 2.7.0 を実行します。この意図的に小さくしたスナップショットには、Requests と urllib3 に関する選定済みのアドバイザリーが 2 件含まれます。これは学習用のデータであり、最新の本番向け脆弱性情報全体ではありません。このコマンドはネットワークリクエストを行いません。

用意されているロック記録を指定します。

course-deps requirements.lock

requests 2.32.3、GHSA-9hjg-9r4m-mvj7、CVE-2024-47081、fixed: 2.32.4 を含む行に続き、Security findings: 1 と表示されるはずです。2 つの ID は、異なるアドバイザリーシステムで同じ問題を示しています。

このアドバイザリーは、特定の細工された URL と、保存されたクライアントの認証情報の組み合わせによって、認証情報が漏えいする可能性に関するものです。ここでは攻撃の再現や、その認証情報の設定は必要ありません。課題は、提供された互換性のある修正版をインストールし、通常のリクエストを維持することです。

既知の問題が見つかると、このコマンドは意図的に終了コード 1 で終了します。CHECK ERROR はスキャンを完了できなかったことを意味し、終了コードは 2 です。安全である証拠にはなりません。重大度の評価は確認の優先順位付けに役立ちますが、このアプリケーションがすでに攻撃されたことを示すものではありません。

レポートには修正済みバージョンが示されます。次に、このレポートを、インストールと再現性のために使うファイルに関連付けます。

要件とインストール済み状態を区別する

このステップでは、バージョンを固定したインストール一覧と、解決済み環境の記録を読み取ります。

cat requirements.txt

各行は package==version の形式です。二重の等号は、そのパッケージを 1 つのバージョンに固定します。このコースの一覧には、直接の依存パッケージと、解決済みの関連パッケージの両方が含まれており、オフラインでインストールを再現できます。

Requests は 2.32.3 に固定されています。スキャンでは、キャッシュで利用できる互換性のある修正版として 2.32.4 が報告されました。関係のない行はすべて維持してください。

cat requirements.lock

ロック記録は、解決された正確なパッケージバージョンを記述します。ここでは、すべてのバージョンを固定した、シンプルな requirements 形式のファイルです。初期状態ではインストール一覧と一致しています。更新後は、テキストの編集だけでパッケージが変わったとみなすのではなく、実際の環境からこの記録を再生成します。

状態は 3 つに分かれています。requirements.txt に書かれた意図するバージョン、.venv 内の実際のパッケージ、requirements.lock に書かれた解決済みの記録です。提供時には、すべてが一致する必要があります。スキャナーが読み取るのは指定したファイルです。実行中のアプリケーションがそのバージョンをインポートしていることまで、自動的に証明するわけではありません。

/opt/labex-dependency-tools/wheels の下にあるキャッシュには、初期のパッケージと修正済みパッケージが用意されています。このキャッシュからインストールするため、オンラインでのバージョン検索や、依存関係の競合解消は不要です。

互換性のある修正版をインストールする

このステップでは、インストール一覧を更新し、実際のプロジェクト環境に修正済みパッケージをインストールします。

nano requirements.txt

requests==2.32.3 だけを requests==2.32.4 に変更します。他の固定バージョンはすべて維持してください。Ctrl+O、Enter、Ctrl+X で保存して終了します。

次に、同じ環境のパッケージマネージャーを使います。install はインストール済みパッケージを変更し、-r requirements.txt は指定したインストール一覧を読み取ります。--no-index はオンラインのパッケージインデックスを無効にし、--find-links は用意された wheel ファイルの場所を pip に指定します。wheel は、ビルド済みの Python インストールパッケージです。

.venv/bin/python -m pip install --no-index --find-links /opt/labex-dependency-tools/wheels -r requirements.txt

Pip は Requests 2.32.3 を 2.32.4 に置き換え、関係のない固定済みパッケージは要件を満たしたままになるはずです。進捗メッセージは異なる場合があるため、指定したバージョン変更を確認してください。システムの pip をそのまま実行すると、別の環境を更新してしまう可能性があるので避けてください。

.venv/bin/python -m pip show requests

Version: 2.32.4 と、このプロジェクトの .venv 内の場所が表示されるはずです。一覧を保存しただけでは、このインストール済み状態は確認できません。クライアントは実行のたびにパッケージをインポートする単発のプログラムなので、以後のリクエストでは更新済み環境を使います。

ロック記録を再生成する

このステップでは、解決済みバージョンの記録を、実際にインストールされているパッケージを表すものにします。

pip freeze は、環境にインストールされているパッケージの固定バージョンを出力します。シェル演算子 > は、その出力をターミナルではなくファイルに書き込み、ファイルの以前の内容を置き換えます。ここでの出力先は、プロジェクトのロック記録です。

.venv/bin/python -m pip freeze > requirements.lock

出力はファイルに書き込まれるため、通常は何も表示されません。ファイルを読み取ります。

cat requirements.lock

Requests は 2.32.4 になり、他の依存パッケージのバージョンは変わらないはずです。並び順や大文字・小文字の違いがあっても、記録されるパッケージは変わりません。

宣言された依存関係を調べる pip check で、パッケージの互換性を確認します。

.venv/bin/python -m pip check

No broken requirements found. と表示されるはずです。このチェックが確認するのはパッケージの互換性であり、アプリケーションの業務動作や、あらゆる脆弱性ではありません。

これで、インストールの意図、インストール済みパッケージ、解決済みの記録が一致しました。ロックファイルは、コマンドの実行を証明するためにコピーしたレポートではなく、実際に再現性を支える成果物です。同じ正確な固定バージョンを生成する、妥当な同等の方法でも条件を満たします。

機能の回帰チェックを実行する

このステップでは、ライブラリを更新しても、元のリクエストとレスポンスが維持されることを確認します。

回帰とは、変更によって以前は動作していた機能が壊れることです。このコースでは、元のクライアントを対象とする小さな機能チェック test.sh を用意しています。ここではチェックの実行を学び、テストの作成は後で学びます。

bash test.sh

次のように表示されるはずです。

PASS: original ticket request and response.

このチェックは実際にローカルのチケットサービスに対してクライアントを実行し、返されたデータを比較します。バージョン文字列の変更を、業務上の成功とみなすものではありません。

自分でもう一度クライアントを実行します。

.venv/bin/python app.py

ID が 1、タイトルが Printer offline の元のチケットが返るはずです。クライアントを削除したり、依存パッケージを取り除いたりしても、この動作は維持できません。

ディスク上のライブラリは更新されており、新しく起動したこのクライアントがそれをインポートします。長時間動作するアプリケーションでは、依存関係の更新後に、管理された手順による再起動が必要な場合があります。このラボのクライアントは毎回新しく実行されます。最後のステップでは、正確なロック記録を使って既知の問題を再確認します。

提供する依存関係の状態を再スキャンする

このステップでは、固定スナップショットによるスキャンと、インストール済みパッケージおよび業務動作の証拠を組み合わせます。

更新したロック記録に対して、同じオフラインスキャナーを実行します。

course-deps requirements.lock

No findings in the selected course snapshot. と表示されるはずです。これは具体的には、選定されたアドバイザリーが記録済みバージョンに一致しなくなったという意味です。そのスナップショットが、現在または将来のすべての問題を網羅していることを示すものではありません。

意図した固定バージョンと、実際にインストールされているパッケージを確認します。

cat requirements.txt
.venv/bin/python -m pip show requests

ファイルでも環境でも、Requests は 2.32.4 で、関係のない固定バージョンは維持されているはずです。前のステップの機能チェックは、更新済みクライアントが引き続き元のリクエストを実行できるという、別の要件を証明します。

完全な修正には、両方の証拠が必要です。定義ファイルだけを編集しても、脆弱なインストール環境が使われ続ける可能性があります。インストール環境を更新しても記録しなければ、後の再現が不確実になります。スキャナーを省略したり、依存パッケージを削除したりするのは、必要なアプリケーションを修正するのではなく、証拠を隠す行為です。

調査文書や、コピーしたスキャナーレポートは不要です。成果物は、実際に更新されたパッケージ環境、正確な固定バージョンの記録、維持された業務動作です。

まとめ

オフラインのアドバイザリーを、実際にインストールされている Python の依存パッケージに結び付け、用意されたキャッシュから互換性のある修正済みパッケージをインストールし、意図するバージョンと解決済みバージョンの記録を同期しました。再スキャンと実際の機能リクエストにより、明示されたコース用スナップショットの範囲内で、対象の修正と動作の維持を確認しました。