この記事の対象読者
- セキュリティ情報を見るたびに「CVSS 9.8(Critical)」と書いてあるが、何を意味するのかよくわからない人
- 脆弱性対応の優先度をチームに説明したいが、「とにかくヤバい」以上の語彙がない人
- PythonスクリプトでCVSSスコアを自動算出したい人
この記事で得られること
- CVSSの基本構造(Base / Temporal / Environmental)を体系的に理解できる
- 各メトリクスの意味と、スコアがどう計算されるかを把握できる
- CVSSスコアを自動算出するPythonスクリプトを手に入れられる
- 実際のCVEを例にスコアの読み方・使い方を実践できる
この記事で扱わないこと
- 個別CVEの詳細な技術分析(それはAIセキュリティシリーズで扱っています)
- CVSS v2以前の旧仕様(本記事はv3.1とv4.0を対象)
- 組織固有のリスク管理フレームワーク(ISO 27001等)の全体像
0. そもそもCVSSがなぜ必要なのか ─ 救急トリアージという比喩
本題に入る前に、この記事全体を貫く比喩を導入しておく。
救急病院に患者が運ばれてきたとき、医師はまず トリアージ(重症度分類) を行う。心停止の患者と軽い切り傷の患者を同じ順番で診るわけにはいかない。限られた医療リソースを最大限に活かすため、「どの患者がどれだけヤバいか」を数値化する共通基準が必要になる。
CVSSは、ソフトウェアの脆弱性に対するトリアージシステムだ。
世界中の病院(=組織)が同じ基準で患者(=脆弱性)の重症度を判定できるように、共通言語としてのスコアリングシステムを提供する。これがCVSS ── Common Vulnerability Scoring Systemである。
CVSSは「シーブイエスエス」と読む。FIRST(Forum of Incident Response and Security Teams)が管理する国際標準だ。
1. CVSSの全体像 ─ 3つのメトリクスグループ
CVSSのスコアは、救急トリアージで言えば「傷の深さ」「出血の速度」「患者の持病」のように、複数の観点を組み合わせて算出される。
具体的には、以下の3つのメトリクスグループから構成される。
| グループ | トリアージ比喩 | 誰が評価するか | 必須/任意 |
|---|---|---|---|
| Base Metrics | 傷そのものの深さ・種類 | 脆弱性の発見者・ベンダー | 必須 |
| Temporal Metrics | 出血の進行速度(時間で変わる) | セキュリティ研究者 | 任意 |
| Environmental Metrics | 患者の持病(組織固有の状況) | 利用者組織 | 任意 |
ニュースやCVEデータベースで目にする「CVSS 9.8」は、ほぼすべて Baseスコアのみ だ。TemporalとEnvironmentalは省略されることが多い。つまり我々が普段見ているのは「傷の深さ」だけで、「出血の速さ」や「持病」は考慮されていない。
ここから各グループを順に深掘りしていこう。
2. Base Metrics ─ 「傷そのもの」を8つの軸で評価する
Base Metricsは、脆弱性そのものの固有の性質を評価する。時間が経っても、環境が変わっても変化しない不変のスコアだ。
救急トリアージで言えば、「刺し傷か・打撲か」「臓器に達しているか」「出血量はどうか」といった、傷そのものの客観的な評価に相当する。
2.1 攻撃元区分(Attack Vector: AV)
「攻撃者はどこから攻撃できるのか?」を評価する。遠くから攻撃できるほど危険度が高い。
| 値 | 略称 | 意味 | スコアへの影響 | トリアージ比喩 |
|---|---|---|---|---|
| Network | N | インターネット越しに攻撃可能 | 最も高い | 空気感染する病原体 |
| Adjacent | A | 同一ネットワーク内から | 高い | 飛沫感染 |
| Local | L | ローカルアクセスが必要 | 中程度 | 接触感染 |
| Physical | P | 物理的に機器に触れる必要あり | 低い | 直接の外傷のみ |
AV:N(Network)の脆弱性は、インターネットに接続しているだけで攻撃対象になる。だからCVSSが高くなりやすく、ニュースにもなりやすい。
2.2 攻撃条件の複雑さ(Attack Complexity: AC)
「攻撃を成功させるのに特殊な条件が必要か?」を評価する。
| 値 | 意味 | トリアージ比喩 |
|---|---|---|
| Low(L) | 特別な条件なしで攻撃可能 | 誰が診ても明らかな重傷 |
| High(H) | 特定の条件(レースコンディション等)が必要 | 特殊な検査をしないと見つからない症状 |
2.3 必要な権限レベル(Privileges Required: PR)
「攻撃者はどのレベルの権限を持っている必要があるか?」
| 値 | 意味 | トリアージ比喩 |
|---|---|---|
| None(N) | 権限不要(未認証で攻撃可能) | 通りすがりの人でも危害を加えられる |
| Low(L) | 一般ユーザー権限が必要 | 病院の患者IDが必要 |
| High(H) | 管理者権限が必要 | 医師のIDカードが必要 |
2.4 ユーザー関与(User Interaction: UI)
「攻撃の成功に被害者の操作(リンクのクリック等)が必要か?」
| 値 | 意味 |
|---|---|
| None(N) | 被害者の操作は不要 |
| Required(R) | 被害者が何らかの操作をする必要がある |
2.5 スコープ(Scope: S)
「脆弱性の影響が、そのコンポーネントの権限範囲を超えるか?」
これがCVSSの中で最もわかりにくいメトリクスだ。トリアージ比喩で言えば、「腕の傷が全身の感染症を引き起こすか」 ── 局所的な問題が他の臓器(=他のシステムコンポーネント)に波及するかどうか、という観点。
| 値 | 意味 | 例 |
|---|---|---|
| Unchanged(U) | 影響範囲は同一コンポーネント内 | Webアプリの脆弱性がWebアプリ内で完結 |
| Changed(C) | 他のコンポーネントに影響が波及 | サンドボックス脱出、VMエスケープ |
Scope: Changed の脆弱性はスコアが大幅に上昇する。「VMから脱出してホストOSを掌握」のようなケースがこれに該当する。
2.6 影響度(CIA Triad)
情報セキュリティの三大要素 ── 機密性(Confidentiality)・完全性(Integrity)・可用性(Availability) ── のそれぞれに対する影響度を評価する。
| 値 | 意味 |
|---|---|
| None(N) | 影響なし |
| Low(L) | 一部の情報/機能に影響 |
| High(H) | 全面的な影響 |
この3つを合わせてCIA Impactと呼ぶ。トリアージで言えば、「どの臓器がどの程度損傷しているか」 のチェック項目だ。
ここまでがBase Metricsの8軸だ。次に、これらの値がどう組み合わさってスコアになるのかを見ていこう。
3. CVSSスコアの計算 ─ 数式の裏側
CVSSスコアは0.0〜10.0の範囲で算出され、以下の重症度ラベルにマッピングされる。
| スコア範囲 | 重症度ラベル | トリアージ色 |
|---|---|---|
| 0.0 | None | なし |
| 0.1 - 3.9 | Low | 緑 |
| 4.0 - 6.9 | Medium | 黄 |
| 7.0 - 8.9 | High | 赤 |
| 9.0 - 10.0 | Critical | 黒(最優先) |
計算式の中核は、攻撃の容易さ(Exploitability)と影響度(Impact)の掛け合わせだ。
\text{BaseScore} = \text{Roundup}\!\Bigl(\min\bigl[(\text{Impact} + \text{Exploitability}),\; 10\bigr]\Bigr)
\text{Exploitability} = 8.22 \times AV \times AC \times PR \times UI
\text{Impact}_{\text{base}} = 1 - \bigl[(1 - C) \times (1 - I) \times (1 - A)\bigr]
Scope: Unchanged の場合:
\text{Impact} = 6.42 \times \text{Impact}_{\text{base}}
Scope: Changed の場合:
\text{Impact} = 7.52 \times [\text{Impact}_{\text{base}} - 0.029] - 3.25 \times [\text{Impact}_{\text{base}} - 0.02]^{15}
各メトリクスの値(AV, AC, PR等)は文字列だが、計算時には所定の数値に変換される。例えば AV:N = 0.85, AV:A = 0.62, AV:L = 0.55, AV:P = 0.20 のように。
数式を見て「...orz」となった方、安心してほしい。次のセクションでPythonスクリプトを使って自動計算する方法を紹介する。
4. PythonでCVSSスコアを算出する
手計算はつらいので、Pythonで自動化しよう。PyPIで公開されている cvss ライブラリを使う。
4.1 インストール
pip install cvss
4.2 CVSSベクタからスコアを算出するスクリプト
"""
CVSS Score Calculator & Diagnostic Tool
────────────────────────────────────────
Usage: python cvss_calc.py "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H"
"""
import sys
from cvss import CVSS3
def calculate_cvss(vector_string: str) -> dict:
"""CVSSベクタ文字列からスコアと重症度を算出する"""
try:
c = CVSS3(vector_string)
except Exception as e:
return {"error": f"無効なCVSSベクタ: {e}"}
base, temporal, environmental = c.scores()
severity = c.severities()[0]
return {
"vector": vector_string,
"base_score": base,
"temporal_score": temporal,
"environmental_score": environmental,
"severity": severity,
}
def diagnose_vector(vector_string: str) -> list[str]:
"""CVSSベクタの各メトリクスを日本語で解説する"""
labels = {
"AV:N": "攻撃元区分: ネットワーク(インターネット越しに攻撃可能)",
"AV:A": "攻撃元区分: 隣接(同一ネットワークが必要)",
"AV:L": "攻撃元区分: ローカル(ローカルアクセスが必要)",
"AV:P": "攻撃元区分: 物理(物理アクセスが必要)",
"AC:L": "攻撃条件: 低(特別な条件なし)",
"AC:H": "攻撃条件: 高(特殊な条件が必要)",
"PR:N": "必要権限: 不要(未認証で攻撃可能)",
"PR:L": "必要権限: 低(一般ユーザー権限)",
"PR:H": "必要権限: 高(管理者権限)",
"UI:N": "ユーザー関与: 不要",
"UI:R": "ユーザー関与: 必要(クリック等)",
"S:U": "スコープ: 変更なし(影響はコンポーネント内)",
"S:C": "スコープ: 変更あり(他コンポーネントに波及)",
"C:N": "機密性への影響: なし",
"C:L": "機密性への影響: 低",
"C:H": "機密性への影響: 高",
"I:N": "完全性への影響: なし",
"I:L": "完全性への影響: 低",
"I:H": "完全性への影響: 高",
"A:N": "可用性への影響: なし",
"A:L": "可用性への影響: 低",
"A:H": "可用性への影響: 高",
}
parts = vector_string.split("/")[1:] # "CVSS:3.1" を除外
results = []
for part in parts:
desc = labels.get(part, f"不明なメトリクス: {part}")
results.append(f" {part:6s} → {desc}")
return results
if __name__ == "__main__":
if len(sys.argv) < 2:
# デモ用: Log4Shell (CVE-2021-44228) のベクタ
vector = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H"
print(f"[デモモード] ベクタ未指定のため Log4Shell を使用します\n")
else:
vector = sys.argv[1]
result = calculate_cvss(vector)
if "error" in result:
print(f"エラー: {result['error']}")
sys.exit(1)
print(f"{'='*50}")
print(f"CVSS Vector : {result['vector']}")
print(f"Base Score : {result['base_score']}")
print(f"Severity : {result['severity']}")
print(f"{'='*50}")
print(f"\n[メトリクス診断]")
for line in diagnose_vector(vector):
print(line)
4.3 実行結果
$ python cvss_calc.py "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H"
==================================================
CVSS Vector : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Base Score : 10.0
Severity : Critical
==================================================
[メトリクス診断]
AV:N → 攻撃元区分: ネットワーク(インターネット越しに攻撃可能)
AC:L → 攻撃条件: 低(特別な条件なし)
PR:N → 必要権限: 不要(未認証で攻撃可能)
UI:N → ユーザー関与: 不要
S:C → スコープ: 変更あり(他コンポーネントに波及)
C:H → 機密性への影響: 高
I:H → 完全性への影響: 高
A:H → 可用性への影響: 高
全メトリクスが最悪値 ── これがCVSS 10.0、トリアージで言えば 「心停止・複数臓器不全・空気感染」 クラスの最緊急事態だ。(;゚д゚)ポカーン
5. Temporal / Environmental Metrics ─ 見落とされがちな残り2つ
ここまでBase Metricsを詳しく見てきたが、CVSSには残り2つのメトリクスグループがある。トリアージ比喩を続けるなら、ここからは 「出血の進行速度」と「患者の持病」 にあたる。
5.1 Temporal Metrics(時間的メトリクス)
脆弱性の「今現在の状況」を反映する。時間とともに変化する。
| メトリクス | 意味 | トリアージ比喩 |
|---|---|---|
| Exploit Code Maturity(E) | 攻撃コードの成熟度 | 「この傷を悪化させる手段が出回っているか」 |
| Remediation Level(RL) | 修正の状態(公式パッチの有無) | 「治療法が確立されているか」 |
| Report Confidence(RC) | 情報の信頼性 | 「診断が確定しているか、疑い段階か」 |
Temporal Metricsは、攻撃コード(Exploit)が公開された瞬間にスコアが上がる。「パッチ未提供 + Exploit公開済み」はゼロデイそのもので、トリアージ最優先だ。
5.2 Environmental Metrics(環境メトリクス)
「自組織にとってどの程度ヤバいか」を評価する。同じ脆弱性でも、組織ごとに影響度は異なる。
| メトリクス | 意味 | トリアージ比喩 |
|---|---|---|
| Confidentiality Requirement(CR) | 機密性の重要度 | 「この患者は免疫不全か」 |
| Integrity Requirement(IR) | 完全性の重要度 | 「この患者は血液凝固障害を持っているか」 |
| Availability Requirement(AR) | 可用性の重要度 | 「この患者にペースメーカーが入っているか」 |
例えば、社内の検証用サーバーなら可用性の要求は低い(AR: Low)が、ECサイトの決済サーバーなら可用性の要求は極めて高い(AR: High)。同じBase Score 7.5でも、Environmental調整後は全く違うスコアになる。
6. 実例で読み解く ─ 有名CVEのCVSSベクタ
ここまでの知識を使って、実在するCVEのCVSSスコアを読み解いてみよう。
6.1 Log4Shell(CVE-2021-44228)── CVSS 10.0
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
| メトリクス | 値 | 意味 |
|---|---|---|
| AV:N | Network | インターネット越しに攻撃可能 |
| AC:L | Low | 特別な条件不要 |
| PR:N | None | 未認証で攻撃可能 |
| UI:N | None | 被害者の操作不要 |
| S:C | Changed | Javaアプリを超えてOS全体に影響 |
| C:H / I:H / A:H | 全High | CIA三要素すべてに全面的影響 |
すべて最悪値。「空気感染・誰でも感染・全臓器不全・他の患者にも感染」── 救急医療で言えば、病院ごと閉鎖するレベルだ。実際、世界中のエンジニアが年末に緊急対応に追われた。
6.2 Heartbleed(CVE-2014-0160)── CVSS 7.5
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
| メトリクス | 値 | 意味 |
|---|---|---|
| S:U | Unchanged | OpenSSL内で完結 |
| C:H | High | メモリ上の秘密鍵等が漏洩 |
| I:N / A:N | None | データ改ざんやサービス停止はない |
機密性のみHigh。トリアージ比喩では「臓器は無事だが、カルテ(秘密情報)が外に漏れた」状態。Scope: Unchangedなのでスコアは10.0にはならないが、影響の深刻さは別問題だ。
6.3 対比で見えるスコアの構造
攻撃の容易さ(Exploitability)は同じだが、ScopeとImpactの差でスコアが大きく変わる。これがCVSSの設計思想だ。
7. CVSS v4.0 ─ 2023年に何が変わったか
2023年11月、FIRSTはCVSS v4.0を正式リリースした。v3.1との主な違いを整理する。
| 変更点 | v3.1 | v4.0 |
|---|---|---|
| メトリクスグループ数 | 3 | 4(Supplementalが追加) |
| Scope(S) | あり | 廃止(AT: Attack Requirementsに再編) |
| Attack Requirements(AT) | なし | 新設(AC:Hの一部を分離) |
| ユーザー関与(UI) | N / R の2値 | N / P(Passive)/ A(Active)の3値 |
| スコア表記 | 7.5 | CVSS-B:7.5 / CVSS-BE:6.2 等(どの評価かを明示) |
| 命名体系 | Base / Temporal / Environmental | Base / Threat / Environmental + Supplemental |
v4.0で「Temporal」は「Threat」に名称変更された。トリアージ比喩で言えば、「出血の速度」から「感染拡大の脅威度」へとニュアンスがシフトした形だ。
v4.0の最大の変更は Scopeの廃止 だ。v3.1のScopeは「わかりにくい」と批判され続けてきた。v4.0ではAttack Requirements(AT)とProvider Urgency等に分割・再編された。
8. よくあるエラーと誤解 ─ トラブルシューティング
CVSSを使う上で陥りがちな罠を整理する。
| # | エラー/誤解 | 原因 | 対処法 |
|---|---|---|---|
| 1 | 「CVSS 9.8だから今すぐパッチを当てろ」と判断する | Base Scoreだけで優先度を決めている | Environmental Metricsで自組織への影響を調整する |
| 2 | CVSSスコアが同じ=同じ危険度だと思う | ベクタが違えばリスクの性質が全く異なる | スコアだけでなくベクタ文字列を必ず確認する |
| 3 | v3.1のベクタをv4.0のツールに入力してエラー | バージョン不一致 | ベクタ先頭の CVSS:3.1/ と CVSS:4.0/ を確認する |
| 4 | Scope: Changed の意味がわからない | CVSS最大の難所 | 「影響が元のコンポーネントを超えるか」で判定する |
| 5 | 「Low(3.9以下)だから無視していい」と思う | 組合せ攻撃(チェイン)の可能性を見落としている | 単体Low + 単体Low = 合わせてCritical級になるケースがある |
| 6 | CVSSだけでリスク判断する | CVSSは脆弱性の技術的深刻度のみ。ビジネスインパクトは評価しない | SSVC等の意思決定フレームワークと併用する |
| 7 | 自社サービスにCVSSを付ける際にScopeで迷う | Scopeの定義が曖昧で判断が分かれる | v4.0ではScopeが廃止されたのでv4.0への移行を検討する |
9. ユースケース別ガイド
ユースケース1: 「脆弱性通知が来たが、対応優先度がわからない」
シナリオ: 依存ライブラリにCVSS 7.8(High)の脆弱性が報告された。パッチ適用にはテストが必要で、即時対応は難しい。
対応フロー:
- CVSSベクタを確認する(スコアだけで判断しない)
-
AV:L(ローカル)なら、外部公開サーバーでなければ優先度を下げられる -
UI:R(ユーザー関与必要)なら、攻撃成立のハードルがある - Environmental Metricsで自組織の状況を反映してスコアを再計算する
ユースケース2: 「自社プロダクトの脆弱性にCVSSスコアを付けたい」
シナリオ: 自社のWebアプリケーションで脆弱性を発見した。CVEを発行してCVSSスコアを付ける必要がある。
対応フロー:
- FIRST公式のCVSS Calculatorを使う: https://www.first.org/cvss/calculator/3.1
- 各メトリクスを1つずつ選択する(上記セクション2の定義を参照)
- ベクタ文字列とスコアをCVE情報に記載する
- 可能であればv4.0でも算出し併記する
ユースケース3: 「チームにCVSSの読み方を教えたい」
シナリオ: 非セキュリティ専門のエンジニアに、CVSSスコアの意味と対応判断を共有したい。
伝え方のポイント:
- 「0〜10の重症度スコア」と説明する(まず大枠)
- 「数字だけでなくベクタ(内訳)を読もう」と伝える
- 本記事のセクション2の表を共有する
- セクション4のPythonスクリプトで実際にスコアを計算させる
10. 学習ロードマップ
CVSSを入口にして、セキュリティ分野のどこに進めるかを整理する。
| レベル | 学ぶべきこと | 推奨リソース |
|---|---|---|
| Level 1 | CVSSスコアの読み方 | 本記事のセクション1〜3 |
| Level 2 | ベクタの実践的な解読・算出 | 本記事のセクション4〜6, FIRST公式Calculator |
| Level 3 | v4.0移行、SSVC併用 | FIRST公式仕様書, CISA SSVCガイド |
| Level 4 | 脆弱性診断、AIセキュリティ | OWASP, ローカルLLM脆弱性シリーズ |
まとめ
CVSSは、脆弱性の「ヤバさ」を世界共通で数値化するトリアージシステムだ。
Base Metricsの8軸(攻撃の容易さ4軸 + 影響度4軸)が核であり、そこに時間的変化(Temporal/Threat)と組織固有の状況(Environmental)を掛け合わせて、最終的なスコアを導く。
正直なところ、筆者も最初はCVSSスコアの数字だけ見て「9.8はヤバい、3.5は放置でOK」と雑に判断していた。しかしベクタの中身を読むようになってから、「AV:LでUI:Rなら外部からは直接攻撃できないじゃないか」「Scope: Changedだから横展開のリスクがあるのか」と、根拠を持って優先度を説明できるようになった。
数字の裏にあるベクタを読む ── それがCVSSを本当に使いこなすということだ。
関連記事
セキュリティ関連の記事はこちらもどうぞ。
LLMやOllamaをローカルで動かす際のセキュリティリスクについても上記で解説しています。