距离计算示例
本示例演示如何计算 CVSS 向量之间的距离,用于相似性分析、聚类和比较安全评估。
概述
距离计算允许您:
- 比较漏洞之间的相似性
- 聚类相似的安全问题
- 识别异常值和异常情况
- 跟踪漏洞随时间的演变
- 优先处理修复工作
基本距离计算
简单距离比较
go
package main
import (
"fmt"
"log"
"math"
"sort"
"sync"
"github.com/scagogogo/cvss-skills/pkg/cvss"
"github.com/scagogogo/cvss-skills/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.ScoreDifference())
fmt.Printf("\n相似性指标:\n")
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 "jaccard":
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()
jaccard := calc.JaccardSimilarity()
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", jaccard, interpretDistance(jaccard, "jaccard"))
}距离算法
欧几里得距离
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 {
vector, err := parser.ParseString(vectorStr)
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 demonstrateJaccardSimilarity() {
// 杰卡德相似度衡量两个向量之间指标匹配的比例
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 {
vector, _ := parser.ParseString(vectorStr)
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.JaccardSimilarity()
fmt.Printf("V%d vs V%d: %.3f (%s)\n",
i+1, j+1, similarity, interpretJaccardSimilarity(similarity))
}
}
}
func interpretJaccardSimilarity(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 {
vector, _ := parser.ParseString(vectorStr)
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 hierarchicalClustering(vectors []*cvss.Cvss3x) {
n := len(vectors)
// 计算距离矩阵
distances := make([][]float64, n)
for i := range distances {
distances[i] = make([]float64, n)
}
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
if i == j {
distances[i][j] = 0
} else {
calc := cvss.NewDistanceCalculator(vectors[i], vectors[j])
distances[i][j] = calc.EuclideanDistance()
}
}
}
// 简单层次聚类(单链接)
clusters := make([][]int, n)
for i := range clusters {
clusters[i] = []int{i}
}
fmt.Println("层次聚类步骤:")
step := 1
for len(clusters) > 1 {
minDist := math.Inf(1)
var mergeI, mergeJ int
// 查找最近的簇
for i := 0; i < len(clusters); i++ {
for j := i + 1; j < len(clusters); j++ {
dist := clusterDistance(clusters[i], clusters[j], distances)
if dist < minDist {
minDist = dist
mergeI, mergeJ = i, j
}
}
}
fmt.Printf("步骤 %d: 合并簇 %v 和 %v(距离: %.3f)\n",
step, clusters[mergeI], clusters[mergeJ], minDist)
// 合并簇
newCluster := append(clusters[mergeI], clusters[mergeJ]...)
newClusters := [][]int{newCluster}
for i, cluster := range clusters {
if i != mergeI && i != mergeJ {
newClusters = append(newClusters, cluster)
}
}
clusters = newClusters
step++
}
}
func clusterDistance(cluster1, cluster2 []int, distances [][]float64) float64 {
minDist := math.Inf(1)
for _, i := range cluster1 {
for _, j := range cluster2 {
if distances[i][j] < minDist {
minDist = distances[i][j]
}
}
}
return minDist
}相似性分析
查找相似向量
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.JaccardSimilarity()
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.JaccardSimilarity()
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 {
vector, _ := parser.ParseString(vectorStr)
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 "jaccard":
distance = calc.JaccardSimilarity()
default:
distance = calc.EuclideanDistance()
}
b.mutex.Lock()
b.cache[key] = distance
b.mutex.Unlock()
return distance
}并行距离矩阵
go
func calculateDistanceMatrixParallel(vectors []*cvss.Cvss3x) [][]float64 {
n := len(vectors)
matrix := make([][]float64, n)
for i := range matrix {
matrix[i] = make([]float64, n)
}
var wg sync.WaitGroup
for i := 0; i < n; i++ {
for j := i; j < n; j++ {
wg.Add(1)
go func(row, col int) {
defer wg.Done()
if row == col {
matrix[row][col] = 0.0
} else {
calc := cvss.NewDistanceCalculator(vectors[row], vectors[col])
distance := calc.EuclideanDistance()
matrix[row][col] = distance
matrix[col][row] = distance // 对称矩阵
}
}(i, j)
}
}
wg.Wait()
return matrix
}实际应用
漏洞优先级排序
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
}下一步
掌握距离计算后,您可以探索: