Skip to content

📏 度量两个 CVSS 向量的相似度 ​

问题 ​

你要的是一个数字——不是一堆差异指标——来说两个 CVSS 向量差多远,用于去重、聚类或“找相似公告”。

方案 ​

流程如下——一个计算器,五种度量,按用途选择:

CLI:distance ​

bash
cvss distance \
  "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" \
  "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L"
text
Euclidean:  0.9670
Manhattan:  2.4600
Hamming:    7
Jaccard:    0.1250
Score diff: 6.0

加 --env 把 11 个环境维度纳入计算:

bash
cvss distance --env \
  "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/E:F/RL:T/RC:C/CR:H/IR:H/AR:H" \
  "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L/E:U/RL:O/RC:R/CR:L/IR:L/AR:L"
text
Euclidean (with env):  1.9850
Manhattan (with env):  5.5700
Hamming (with env):    13
Jaccard (with env):    0.4091
Score diff: 7.4

要机器消费,用 --format json:

bash
cvss distance --format json \
  "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" \
  "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L"
json
{
  "euclidean": 0.9669539802906858,
  "hamming": 7,
  "jaccard": 0.125,
  "manhattan": 2.46,
  "score_diff": 6.000000000000001,
  "vector1": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
  "vector2": "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L"
}

Go SDK:DistanceCalculator ​

go
package main

import (
	"fmt"

	"github.com/scagogogo/cvss-skills/pkg/cvss"
	"github.com/scagogogo/cvss-skills/pkg/parser"
)

func main() {
	a, _ := parser.ParseString("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
	b, _ := parser.ParseString("CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L")

	dc := cvss.NewDistanceCalculator(a, b)
	fmt.Printf("Euclidean : %.4f\n", dc.EuclideanDistance())
	fmt.Printf("Manhattan : %.4f\n", dc.ManhattanDistance())
	fmt.Printf("Hamming   : %d\n", dc.HammingDistance())
	fmt.Printf("Jaccard   : %.4f\n", dc.JaccardSimilarity())
	fmt.Printf("ScoreDiff : %.1f\n", dc.ScoreDifference())

	// 带环境指标的变体
	fmt.Printf("Euclidean (env): %.4f\n", dc.EuclideanDistanceWithEnv())

	// 带错误返回的变体——基础指标不完整时会显式报错
	if _, err := dc.EuclideanDistanceChecked(); err != nil {
		fmt.Println("checked error:", err)
	}
}

如何选度量 ​

度量衡量的是什么范围适用场景
Hamming不同的指标个数整数 0–11(基础)你要“差几个旋钮”,每个差异等权
Jaccard相同 / 总指标0–1(1 = 完全相同)你要一个 [0,1] 的归一化相似度
Euclidean√(Σ 分数差²)≥ 0你在意分数空间差异的幅度,离群差异权重更大
ManhattanΣ |分数差|≥ 0同 Euclidean,但对单个大离群更鲁棒
Score diff|score(a) − score(b)|0–10你只关心最终那个数,单维度

Jaccard 是相似度,不是距离

JaccardSimilarity 对完全相同的向量返回 1.0,对完全不相交的返回 0.0。需要一个“相同为 0”的距离时,用 1 - jaccard 转换。

讨论 ​

  • plain 变体在不完整基础指标上静默返回 0。 任一向量缺必需基础指标时,EuclideanDistance() 等返回 0.0——和“完全相同”看不出区别。用 *Checked 变体(EuclideanDistanceChecked())拿到显式错误。
  • PR 和 UI 用的是上下文调整后的分数。 PR 的分数依赖 Scope,而 UI:R 在 v3.0 是 0.56、v3.1 是 0.62——距离计算已经考虑了这点,所以跨版本对比是有意义的。
  • Scope 是 0/1,不是分数。 Scope没有数值分数,距离代码把 scope 变化当成固定 1.0 的贡献。
  • --env 只在两边都有环境指标时才加维度。 只有一边有时,env 变体会退回 base+temporal 的行为。
  • 不是你想要的? 要逐指标的人话版对比,看 对比两个向量。

另见 ​

基于 MIT 许可证发布。