脆弱性スキャン導入で500件アラートに溺れた話|1年で落ち着いた実装順序
脆弱性スキャンとペネテスト導入した1年間。最初の地獄から抜け出した秘訣は実装順序でした。False Positive対策とチームが実際にハマったポイントを正直に共有します。
脆弱性スキャン・ペネトレーションテスト2026|本番導入で地雷を踏んだ1年の実装記
先日チームで脆弱性スキャンとペネトレーションテストの本格導入を決めたんですけど、正直最初の3ヶ月は地獄でした。アラートが毎週500件、その中から本当に対応すべき脆弱性を見つけるのに数時間費やす日々。でも1年運用してようやく「これなら運用できる」という形が見えてきたので、実装で得た知見を共有します。
脆弱性スキャンツール、実装順序が全てだった
最初の失敗は「とりあえずオープンソースでいいでしょ」という安易な判断でした。OWASP ZAPとNessusを同時導入したんですけど、結果として False Positive の嵐に吞まれました。
うちのチームが実装した順序がこれです。この流れが本当に重要なんですよね。反対にやると、DAST で検出した大量のアラートに SAST が反応して、結局何も対応されないという地獄が発生します。
graph LR
A["1. SCA<br/>依存関係"] --> B["2. SAST<br/>静的解析"]
B --> C["3. DAST<br/>動的解析"]
C --> D["4. ペネテスト<br/>人間評価"]
実装したツール構成がこちらです。個人的には Snyk + Semgrep の組み合わせが、2026年時点ではコストと精度のバランスが一番マシだと感じています。
| ツール | カテゴリ | 導入タイミング | 月額コスト | 正直な感想 |
|---|---|---|---|---|
| Snyk | SCA | 1ヶ月目 | $500〜 | CVE 更新が早い。プルリク自動作成も地味に便利 |
| Semgrep | SAST | 2ヶ月目 | $200〜 | ルールカスタマイズ性が高い。False Positive は少なめ |
| OWASP ZAP | DAST | 3ヶ月目 | 無料 | OSSだけど本番用には辛い。アラート多すぎで正直使いづらい |
| Burp Suite Pro | 手動テスト | 6ヶ月目 | $600/年 | 本当のペネテストはこれが必須。自動化だけじゃ足りない |
素直に言うと、最初から有料ツールに投資すればよかった。OSSで試行錯誤するのに3ヶ月費やしてしまい、その間にセキュリティ負債が積み上がりました。
CVSS スコア信仰が地獄を生んでいた
うちのチームが陥った最大の落とし穴が「CVSS スコア 7.0 以上は全部対応する」という単純な判定基準でした。これやると絶対失敗します。
実装したのが「リスク評価マトリックス」で、CVSS スコアと実装環境のコンテキストを組み合わせる仕組みです。環境での露出度と実装可能性を加味することで、本当に対応すべき脆弱性を見分けられるようになりました。
# リスク評価ロジック
def calculate_risk_score(cvss_score, exposure):
"""
実際の環境リスクを計算
CVSS スコア + 実装環境の露出度
"""
# 基本スコア
base_risk = cvss_score * 10
# 露出度調整
if exposure == "public":
exposure_factor = 1.5
elif exposure == "internal_network":
exposure_factor = 0.8
elif exposure == "localhost_only":
exposure_factor = 0.2
else:
exposure_factor = 1.0
# 実装可能性
if is_poc_available():
impl_factor = 1.3
else:
impl_factor = 0.7
actual_risk = base_risk * exposure_factor * impl_factor
return min(actual_risk, 100)
# 例:CVSS 8.2 の脆弱性でも
risk_public = calculate_risk_score(8.2, "public") # 100 → 対応必須
risk_localhost = calculate_risk_score(8.2, "localhost_only") # 15 → 後回しOK
このロジックで優先順位をつけることで、対応すべき脆弱性が実際には 20% に絞られました。CVSS だけだと 80% が「本来対応する必要がない」やつなんですよね。
False Positive との付き合い方、1年で見えた現実
ペネトレーションテストで本当に面倒なのが False Positive です。最初は「ツールが検出したなら本当の脆弱性だ」と思ってました。大間違いでした。ツールノイズと本物の脆弱性を区別する方法を考えたのが、この検証フローです。
graph TD
A[アラート検出] --> B{CVSS >= 7.0?}
B -->|No| C[後回し]
B -->|Yes| D{実装環境で露出?}
D -->|No| E[False Positive判定]
D -->|Yes| F{PoC実装可能?}
F -->|No| G[低優先度]
F -->|Yes| H{実装に3日以上?}
H -->|Yes| I{リスク評価ハイ?}
I -->|Yes| J[即時対応]
I -->|No| K[スプリント計画に追加]
H -->|No| L[この週末に対応]
実装して気づいたのが「90% の脆弱性は、うちのアーキテクチャでは実装不可能」ということです。例えば XSS が検出されても、API レイヤーのレスポンスにまで到達しないケースが大半なんですよね。CORS 設定で既に防がれてるんです。
本番環境でテストして初めて「あ、これ実装できないな」って気づく。だから DAST は本番環境で定期実行するのが正解だと学びました。ステージング だけではダメです。
ペネトレーションテスト、自動化で手を抜いた話
素直に告白すると、最初は「ペネトレーションテストなんて自動化ツールでいいでしょ」と思ってました。3ヶ月後に気づきました。大間違いです。
Burp Suite で自動スキャン走らせたら 1200 件のアラート。その中から実装可能な脆弱性を見つけるのに丸2日費やしました。その時点で「こういう単純作業は人間がやるべき」って判断して、外部のセキュリティコンサル会社に依頼しました。
1回のペネトレーションテスト(3営業日) =$15万円くらい。うちのチームで同じことをやろうとすると、セキュリティエンジニアの時給換算で月$30万超えます。だから年 2 回、外部委託が現実的です。
むしろ自動化ツールは「定期的にスキャンして、人間が見落としたやつだけ報告」という使い方が正解だと判断しました。
脆弱性検出後の対応フローが想像以上に重い
ここが本当に見落としがちなポイントなんですが、脆弱性を 検出する ことと 対応する ことは全く別の話です。
検出した脆弱性 1 件ごとに必要な作業は、かなりの時間を要します:
- 検証 (本当に脆弱性か確認): 30分
- リスク評価 (実装環境での影響判断): 30分
- 対応計画 (修正方法の検討): 1時間
- 実装 (コード修正): 2〜8時間(脆弱性によって大きく異なる)
- テスト (修正確認+回帰テスト): 2〜4時間
- デプロイ (本番リリース): 1時間
計:6.5 〜 15.5 時間
つまり CVSS 7.0 以上の脆弱性が 50 件見つかったら、単純計算で 325 〜 775 時間 必要です。これ、チーム全体で対応しても 2 ヶ月かかります。だから「全ての脆弱性に対応する」という目標は最初から不可能。実装環境で本当に影響がある脆弱性を優先する という判断が生死を分けます。
実装した優先度ルールがこれです。このルールを明文化することで、「何を対応するか」という議論が一気に減りました。
優先度1(即日対応):
- CVSS >= 9.0
- OR: 本番で実装可能な RCE
- OR: 認証回避
優先度2(1週間以内):
- CVSS 7.0 - 8.9
- AND: 本番環境で露出
優先度3(スプリント計画):
- CVSS 5.0 - 6.9
- OR: 実装に時間がかかる
優先度4(後回し):
- CVSS < 5.0
- AND: 実装環境で露出なし
SOC2 審査との組み合わせで見えた現実
うちのチームが SOC2 対応をしたときに、セキュリティ監査人から言われたのが「自動スキャンツールの結果だけでは証拠にならない。人間による評価が必須」ということでした。これが地味に重い作業だったんですよね。
だから構築した検査フローが:
- 月 1 回 → 自動脆弱性スキャン(SCA + SAST + DAST)
- 四半期 1 回 → 外部ペネトレーションテスト
- 年 1 回 → SOC2 審査
これで「実装環境で本当に対応すべき脆弱性」と「ツールノイズ」が区別できるようになりました。データで見るとこんな感じです:
xychart-beta
title "脆弱性対応スケジュール(年間)"
x-axis [Q1, Q2, Q3, Q4]
y-axis "対応脆弱性数" 0 --> 50
line [15, 12, 18, 8]
line [3, 2, 4, 2]
line [18, 14, 22, 10]
青が月間自動スキャン、オレンジが外部ペネテスト、緑がトータルです。
ツール間の連携で生産性が 10 倍変わった
最初は Snyk で検出 → スプレッドシートに手入力 → ステータス管理という地獄でした。毎週「あの脆弱性どうなった?」という確認メールが飛んできて、もう二度とこんなことはしたくないと思いました。
実装した統合フロー:
graph TB
subgraph "検出フェーズ"
A[Snyk SCA] --> D[Webhook]
B[Semgrep SAST] --> D
C[OWASP ZAP DAST] --> D
end
subgraph "集約フェーズ"
D --> E[Jira API]
E --> F[自動チケット作成]
end
subgraph "対応フェーズ"
F --> G[優先度判定ロジック]
G --> H[通知/Slack]
G --> I[ダッシュボード]
end
subgraph "フィードバック"
J[修正完了] --> K[再スキャン]
K --> L{脆弱性消滅?}
L -->|Yes| M[自動クローズ]
L -->|No| N[再トリアージ]
end
これで手作業が 80% 削減されました。正直、ツール統合に 2 週間費やした価値はありました。
2026 年の脆弱性スキャン、実装しておくべき 5 つのこと
本当に効いた施策がこれです。1年運用して、この 5 つが本当に重要だと確信しました。
- CVSS スコア信仰を捨てる → 実装環境のコンテキストが 90% を占める
- 自動スキャンと人間による評価を分ける → ツールだけでは不可能
- 優先度ルールを明文化 → 曖昧だと絶対に運用崩壊する
- ツール統合で手作業を減らす → Webhook + 自動チケット作成が必須
- 定期ペネトレーションテストを外部委託 → 自前でやるコストに見合わない
あと痛感したのが「セキュリティは追加作業ではなく、開発フローに組み込む」ということです。検証フェーズで脆弱性を検出するのではなく、CI/CD パイプラインで自動検出して、本番リリース前に対応する。これができるかどうかが全てなんですよね。
まとめ
脆弱性スキャン・ペネトレーションテストを本番導入するなら、覚悟しておくべきことがあります。
CVSS スコアだけで判断するな、実装環境での露出度が最重要です。False Positive 対策に 3 ヶ月かけるくらいの覚悟を決めてください。最初は大量アラートに吞まれます。ツール統合に 2 週間投資する価値は絶対ありますし、自動化ツール + 人間による定期テストの組み合わせが正解です。どちらか一方では不十分なんですよ。あと優先度ルールを明文化しないと、曖昧さで絶対に運用が崩壊します。
チームで導入を考えてるなら、最初の 3 ヶ月は本当に覚悟してください。False Positive に吞まれます。でも 1 年続ければ、本当に対応すべき脆弱性だけが浮かぶようになります。あとは インシデント対応の最新ベストプラクティス と組み合わせれば、セキュリティ体制がようやく回り始めますよ。