はじめに
企業のセキュリティ担当や情シス担当にとって、日々公開される「脆弱性情報」のキャッチアップと管理は頭の痛いタスクです。 特にAndroidの脆弱性は毎月大量に公開されるため、管理コストがかさみます。さらに、今回は諸事情により、過去数年分をまとめてExcelシートに転記して管理する必要があったため、以下のような課題がありました。
-
工数増: Android Security Bulletin(公式)を目視確認し、Excelに転記するのが大変。年によっては500件を超えることもあります
-
情報不足: 公式情報だけでは「CVSSスコア」や「詳細な影響」が分からず、別のDB(Tenableなど)を検索する必要がある
-
転記ミス: 手作業によるコピー&ペーストはミスが起きやすい
これらの課題を解決するため、「情報の自動収集」から「詳細情報の補完」までを一気通貫で行うPythonスクリプトを作成しました。
Excelシート転記作業の概要
Step1
下記のAndroidの公式サイトからCVE,重大度、更新対象のAOSPバージョンを、それぞれExcelファイルのCVE,Rank,Categoryの欄に記入します。Solutionの欄にはサイトのURLを転記し、公開日の欄には、サイトのページが何年の何月のものかを判断して記載します。
Step2
そして、tenableのサイト(https://www.tenable.com/cve/{対象の課題となるCVE}) にアクセスして、DescriptionとCVSS v3をExcelに転記します。
作成したツールの概要
今回作成したのは、以下の2段階(パイプライン)で処理を行うツールセットです。
| Step | Script File | Role |
|---|---|---|
| Step 1 | Webスクレイピング (公式) |
source.android.comを巡回し、指定年の全脆弱性をExcel化して、CVE,Rank,Category,Solution,公開日の欄を転記します。 |
| Step 2 | 詳細情報エンリッチ (Tenable) | Excel内のCVE IDを元に外部DBを検索し、CVSS v3スコアとDescriptionの欄に追記する。 |
GitHubリポジトリはこちら
技術的な壁と乗り越えた工夫
開発中に直面した最大の壁は、Step 2の詳細情報取得における 「動的サイト(Next.js)のスクレイピング」 でした。
課題:HTMLにデータがない?
当初、BeautifulSoup でHTMLを解析してCVSSスコアを取得しようとしました。しかし、対象サイト(Tenable)は Next.js で構築されており、アクセス直後のHTMLソースには肝心の数値データが含まれておらず、JavaScriptによって後からレンダリングされる仕様でした。
Seleniumなどのブラウザ操作ツールを使えば取得できますが、処理が重く、数百件のループ処理には不向きです。
解決策:隠れたJSONデータを直撃する
ページのHTMLソースを詳細に分析したところ、Next.jsが初期データとして保持している <script id="__NEXT_DATA__"> タグ内に、必要なデータが全てJSON形式で格納されていることを発見しました。
そこで、以下のようなロジックを実装しました。
-
HTML内の NEXT_DATA スクリプトタグを抽出
-
中身を json.loads でパースして辞書型に変換
-
辞書の中から再帰的に cvss3 や base_score といったキーを探索
# 実装の一部抜粋
def extract_score_from_json(data):
"""JSONデータからCVSS v3スコアを探し出す"""
# 再帰的にキーを探すヘルパー関数を利用
cvss3_data = find_key_in_json(data, 'cvss3')
if cvss3_data:
# base_scoreなどのキーから値を取得
score = cvss3_data.get('base_score') or cvss3_data.get('score')
return str(score)
return None
これにより、ブラウザを起動することなく、高速かつ100%正確にデータを取得することに成功しました。
その他のこだわりポイント
1. CVSS v3の厳密な特定
脆弱性スコアには古い「v2」と新しい「v3」が混在しています。単純なテキスト検索ではv2を拾ってしまうことがあるため、JSON構造解析と正規表現による近傍探索を組み合わせ、v3スコアを優先的に特定するアルゴリズムを実装しました。
2. 堅牢なリトライ処理
数百件のURLに連続アクセスするため、ネットワークの一時的なエラーは避けられません。
-
取得に失敗した行をメモリに保持
-
全件処理終了後に、失敗分のみを対象に自動リトライを実行
この仕組みにより、夜間にバッチ実行しても「途中で止まってデータが欠ける」リスクを最小限に抑えています。
実行結果
Before: 手作業で1件ずつ検索・転記(100件で約2〜3時間)。
After: スクリプトを実行して待つだけ(数分で完了)。工数をほぼゼロに削減できました。
おわりに
今回の開発を通じて、単なるスクレイピングだけでなく、Webフレームワーク(Next.js)の仕組みを理解した上でのデータ抽出 の重要性を学びました。 今後はこの技術を応用して、業務効率化に取り組んでいきたいです。



