距离计算示例
本示例演示如何计算 CVSS 向量之间的距离,用于相似性分析、聚类和比较安全评估。
概述
距离计算允许您:
- 比较漏洞之间的相似性
- 聚类相似的安全问题
- 识别异常值和异常情况
- 跟踪漏洞随时间的演变
- 优先处理修复工作
基本距离计算
简单距离比较
go
package main
import (
"fmt"
"log"
"github.com/scagogogo/cvss-parser/pkg/cvss"
"github.com/scagogogo/cvss-parser/pkg/parser"
)
func main() {
// 解析两个 CVSS 向量
vector1Str := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
vector2Str := "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L"
parser1 := parser.NewCvss3xParser(vector1Str)
vector1, err := parser1.Parse()
if err != nil {
log.Fatal(err)
}
parser2 := parser.NewCvss3xParser(vector2Str)
vector2, err := parser2.Parse()
if err != nil {
log.Fatal(err)
}
// 创建距离计算器
calc := cvss.NewDistanceCalculator(vector1, vector2)
// 计算不同的距离指标
fmt.Printf("向量 1: %s\n", vector1.String())
fmt.Printf("向量 2: %s\n", vector2.String())
fmt.Printf("\n距离指标:\n")
fmt.Printf(" 欧几里得距离: %.3f\n", calc.EuclideanDistance())
fmt.Printf(" 曼哈顿距离: %.3f\n", calc.ManhattanDistance())
fmt.Printf(" 切比雪夫距离: %.3f\n", calc.ChebyshevDistance())
fmt.Printf("\n相似性指标:\n")
fmt.Printf(" 余弦相似度: %.3f\n", calc.CosineSimilarity())
fmt.Printf(" 雅卡德相似度: %.3f\n", calc.JaccardSimilarity())
}
距离解释
go
func interpretDistance(distance float64, algorithm string) string {
switch algorithm {
case "euclidean":
if distance < 0.5 {
return "非常相似"
} else if distance < 1.0 {
return "相似"
} else if distance < 2.0 {
return "有些不同"
} else {
return "非常不同"
}
case "cosine":
if distance > 0.9 {
return "非常相似"
} else if distance > 0.7 {
return "相似"
} else if distance > 0.3 {
return "有些相似"
} else {
return "非常不同"
}
default:
return "未知"
}
}
func analyzeVectorSimilarity(v1, v2 *cvss.Cvss3x) {
calc := cvss.NewDistanceCalculator(v1, v2)
euclidean := calc.EuclideanDistance()
cosine := calc.CosineSimilarity()
fmt.Printf("相似性分析:\n")
fmt.Printf(" 向量 1: %s\n", v1.String())
fmt.Printf(" 向量 2: %s\n", v2.String())
fmt.Printf(" 欧几里得: %.3f (%s)\n", euclidean, interpretDistance(euclidean, "euclidean"))
fmt.Printf(" 余弦: %.3f (%s)\n", cosine, interpretDistance(cosine, "cosine"))
}
距离算法
欧几里得距离
go
func demonstrateEuclideanDistance() {
vectors := []string{
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", // 严重网络
"CVSS:3.1/AV:N/AC:L/PR:L/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", // 低本地
}
parsedVectors := make([]*cvss.Cvss3x, len(vectors))
for i, vectorStr := range vectors {
parser := parser.NewCvss3xParser(vectorStr)
vector, err := parser.Parse()
if err != nil {
log.Fatal(err)
}
parsedVectors[i] = vector
}
fmt.Println("欧几里得距离矩阵:")
fmt.Printf("%10s", "")
for i := range parsedVectors {
fmt.Printf("%10s", fmt.Sprintf("V%d", i+1))
}
fmt.Println()
for i, v1 := range parsedVectors {
fmt.Printf("%10s", fmt.Sprintf("V%d", i+1))
for _, v2 := range parsedVectors {
if v1 == v2 {
fmt.Printf("%10s", "0.000")
} else {
calc := cvss.NewDistanceCalculator(v1, v2)
distance := calc.EuclideanDistance()
fmt.Printf("%10.3f", distance)
}
}
fmt.Println()
}
}
曼哈顿距离
go
func demonstrateManhattanDistance() {
// 曼哈顿距离对于理解所有指标的总差异很有用
vector1Str := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
vector2Str := "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L"
parser1 := parser.NewCvss3xParser(vector1Str)
vector1, _ := parser1.Parse()
parser2 := parser.NewCvss3xParser(vector2Str)
vector2, _ := parser2.Parse()
calc := cvss.NewDistanceCalculator(vector1, vector2)
manhattan := calc.ManhattanDistance()
fmt.Printf("曼哈顿距离分析:\n")
fmt.Printf("向量 1: %s\n", vector1.String())
fmt.Printf("向量 2: %s\n", vector2.String())
fmt.Printf("曼哈顿距离: %.3f\n", manhattan)
fmt.Printf("解释: %s\n", interpretManhattanDistance(manhattan))
}
func interpretManhattanDistance(distance float64) string {
if distance < 1.0 {
return "非常相似的向量"
} else if distance < 3.0 {
return "中等相似的向量"
} else if distance < 5.0 {
return "有些不同的向量"
} else {
return "非常不同的向量"
}
}
余弦相似度
go
func demonstrateCosineSimilarity() {
// 余弦相似度对于理解方向相似性很有用,不考虑大小
vectors := []string{
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L", // 相似模式,较低可用性
"CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L", // 不同模式
}
parsedVectors := make([]*cvss.Cvss3x, len(vectors))
for i, vectorStr := range vectors {
parser := parser.NewCvss3xParser(vectorStr)
vector, _ := parser.Parse()
parsedVectors[i] = vector
}
fmt.Println("余弦相似度分析:")
for i := 0; i < len(parsedVectors); i++ {
for j := i + 1; j < len(parsedVectors); j++ {
calc := cvss.NewDistanceCalculator(parsedVectors[i], parsedVectors[j])
similarity := calc.CosineSimilarity()
fmt.Printf("V%d vs V%d: %.3f (%s)\n",
i+1, j+1, similarity, interpretCosineSimilarity(similarity))
}
}
}
func interpretCosineSimilarity(similarity float64) string {
if similarity > 0.95 {
return "几乎相同的模式"
} else if similarity > 0.8 {
return "非常相似的模式"
} else if similarity > 0.6 {
return "中等相似的模式"
} else if similarity > 0.3 {
return "有些相似的模式"
} else {
return "不同的模式"
}
}
向量聚类
K-Means 风格聚类
go
func clusterVectors(vectors []*cvss.Cvss3x, threshold float64) [][]int {
var clusters [][]int
used := make([]bool, len(vectors))
for i, vector1 := range vectors {
if used[i] {
continue
}
cluster := []int{i}
used[i] = true
for j, vector2 := range vectors {
if i == j || used[j] {
continue
}
calc := cvss.NewDistanceCalculator(vector1, vector2)
distance := calc.EuclideanDistance()
if distance <= threshold {
cluster = append(cluster, j)
used[j] = true
}
}
clusters = append(clusters, cluster)
}
return clusters
}
func demonstrateClustering() {
vectors := []string{
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", // 严重网络
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L", // 严重网络(相似)
"CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", // 严重本地
"CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L", // 严重本地(相似)
"CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L", // 低严重性
"CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:N", // 低严重性(相似)
}
parsedVectors := make([]*cvss.Cvss3x, len(vectors))
for i, vectorStr := range vectors {
parser := parser.NewCvss3xParser(vectorStr)
vector, _ := parser.Parse()
parsedVectors[i] = vector
}
clusters := clusterVectors(parsedVectors, 0.5)
fmt.Printf("聚类结果(阈值: 0.5):\n")
for i, cluster := range clusters {
fmt.Printf("聚类 %d (%d 个向量):\n", i+1, len(cluster))
for _, idx := range cluster {
fmt.Printf(" [%d] %s\n", idx, vectors[idx])
}
fmt.Println()
}
}
相似性分析
查找相似向量
go
func findSimilarVectors(target *cvss.Cvss3x, candidates []*cvss.Cvss3x, threshold float64) []SimilarVector {
var similar []SimilarVector
for i, candidate := range candidates {
calc := cvss.NewDistanceCalculator(target, candidate)
distance := calc.EuclideanDistance()
similarity := calc.CosineSimilarity()
if distance <= threshold {
similar = append(similar, SimilarVector{
Index: i,
Vector: candidate,
Distance: distance,
Similarity: similarity,
})
}
}
// 按距离排序(最相似的在前)
sort.Slice(similar, func(i, j int) bool {
return similar[i].Distance < similar[j].Distance
})
return similar
}
type SimilarVector struct {
Index int
Vector *cvss.Cvss3x
Distance float64
Similarity float64
}
func (sv SimilarVector) String() string {
return fmt.Sprintf("[%d] %s (距离: %.3f, 相似度: %.3f)",
sv.Index, sv.Vector.String(), sv.Distance, sv.Similarity)
}
最近邻
go
func findNearestNeighbors(target *cvss.Cvss3x, candidates []*cvss.Cvss3x, k int) []SimilarVector {
var neighbors []SimilarVector
for i, candidate := range candidates {
calc := cvss.NewDistanceCalculator(target, candidate)
distance := calc.EuclideanDistance()
similarity := calc.CosineSimilarity()
neighbors = append(neighbors, SimilarVector{
Index: i,
Vector: candidate,
Distance: distance,
Similarity: similarity,
})
}
// 按距离排序
sort.Slice(neighbors, func(i, j int) bool {
return neighbors[i].Distance < neighbors[j].Distance
})
// 返回前 k 个邻居
if k > len(neighbors) {
k = len(neighbors)
}
return neighbors[:k]
}
func demonstrateNearestNeighbors() {
target := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
candidates := []string{
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L", // 非常相似
"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", // 相似
"CVSS:3.1/AV:L/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", // 不同
}
// 解析目标
targetParser := parser.NewCvss3xParser(target)
targetVector, _ := targetParser.Parse()
// 解析候选者
candidateVectors := make([]*cvss.Cvss3x, len(candidates))
for i, candidateStr := range candidates {
candidateParser := parser.NewCvss3xParser(candidateStr)
vector, _ := candidateParser.Parse()
candidateVectors[i] = vector
}
// 查找最近邻
neighbors := findNearestNeighbors(targetVector, candidateVectors, 3)
fmt.Printf("目标: %s\n", target)
fmt.Printf("前 3 个最近邻:\n")
for i, neighbor := range neighbors {
fmt.Printf("%d. %s\n", i+1, neighbor.String())
}
}
异常检测
统计异常值检测
go
func detectAnomalies(vectors []*cvss.Cvss3x, threshold float64) []int {
var anomalies []int
for i, vector1 := range vectors {
var totalDistance float64
var count int
for j, vector2 := range vectors {
if i == j {
continue
}
calc := cvss.NewDistanceCalculator(vector1, vector2)
totalDistance += calc.EuclideanDistance()
count++
}
avgDistance := totalDistance / float64(count)
if avgDistance > threshold {
anomalies = append(anomalies, i)
}
}
return anomalies
}
func demonstrateAnomalyDetection() {
vectors := []string{
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", // 正常高严重性
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L", // 正常高严重性
"CVSS:3.1/AV:N/AC:L/PR:L/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", // 正常低严重性
"CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:N", // 正常低严重性
"CVSS:3.1/AV:P/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:H", // 异常:物理访问但高可用性影响
}
parsedVectors := make([]*cvss.Cvss3x, len(vectors))
for i, vectorStr := range vectors {
parser := parser.NewCvss3xParser(vectorStr)
vector, _ := parser.Parse()
parsedVectors[i] = vector
}
anomalies := detectAnomalies(parsedVectors, 2.0)
fmt.Printf("异常检测结果(阈值: 2.0):\n")
if len(anomalies) == 0 {
fmt.Println("未检测到异常")
} else {
fmt.Printf("检测到 %d 个异常:\n", len(anomalies))
for _, idx := range anomalies {
fmt.Printf(" [%d] %s\n", idx, vectors[idx])
}
}
}
性能优化
批量距离计算
go
type BatchDistanceCalculator struct {
vectors []*cvss.Cvss3x
cache map[string]float64
mutex sync.RWMutex
}
func NewBatchDistanceCalculator(vectors []*cvss.Cvss3x) *BatchDistanceCalculator {
return &BatchDistanceCalculator{
vectors: vectors,
cache: make(map[string]float64),
}
}
func (b *BatchDistanceCalculator) GetDistance(i, j int, algorithm string) float64 {
if i == j {
return 0.0
}
// 确保缓存键的一致顺序
if i > j {
i, j = j, i
}
key := fmt.Sprintf("%d-%d-%s", i, j, algorithm)
b.mutex.RLock()
if distance, exists := b.cache[key]; exists {
b.mutex.RUnlock()
return distance
}
b.mutex.RUnlock()
calc := cvss.NewDistanceCalculator(b.vectors[i], b.vectors[j])
var distance float64
switch algorithm {
case "euclidean":
distance = calc.EuclideanDistance()
case "manhattan":
distance = calc.ManhattanDistance()
case "cosine":
distance = calc.CosineSimilarity()
default:
distance = calc.EuclideanDistance()
}
b.mutex.Lock()
b.cache[key] = distance
b.mutex.Unlock()
return distance
}
实际应用
漏洞优先级排序
go
func prioritizeVulnerabilities(vulnerabilities []*cvss.Cvss3x, criticalThreshold float64) []int {
var priorities []int
// 查找严重漏洞
var criticalVulns []*cvss.Cvss3x
for i, vuln := range vulnerabilities {
calculator := cvss.NewCalculator(vuln)
score, _ := calculator.Calculate()
if score >= criticalThreshold {
criticalVulns = append(criticalVulns, vuln)
priorities = append(priorities, i)
}
}
// 按与最严重漏洞的相似性排序
if len(criticalVulns) > 0 {
mostCritical := criticalVulns[0]
sort.Slice(priorities, func(i, j int) bool {
calc1 := cvss.NewDistanceCalculator(mostCritical, vulnerabilities[priorities[i]])
calc2 := cvss.NewDistanceCalculator(mostCritical, vulnerabilities[priorities[j]])
return calc1.EuclideanDistance() < calc2.EuclideanDistance()
})
}
return priorities
}
下一步
掌握距离计算后,您可以探索: