1.CVSS 4.0 分数计算公式

CVSS名称CVSS 指标
CVSS-B基础指标
CVSS-BE基础和环境指标
CVSS-BT基础和威胁指标
CVSS-BTE基础、威胁和环境指标

1.1 各指标内容及说明

1.1.1 基本指标

1.1.1.1 利用难度指标
名称指标默认
攻击向量 (AV)网络(N)/相邻网络(A)/本地网络(L)N
攻击复杂度 (AC)低 (L)/高(H)L
攻击要求 (AT)无 (N)/存在 §N
特权要求 (PR)无 (N)/低 (L)/高 (H)N
交互 (UI)无 (N)/被动的 §/主动的 (A)N
1.1.1.2 易受攻击系统影响指标
名称指标默认
机密性 (VC)高 (H)/低 (L)/无 (N)N
完整性 (VI)高 (H)/低 (L)/无 (N)N
可用性 (VA)高 (H)/低 (L)/无 (N)N
1.1.1.3 后续影响指标
名称指标默认
机密性 (SC)高 (H)/低 (L)/无 (N)N
完整性 (SI)高 (H)/低 (L)/无 (N)N
可用性 (SA)高 (H)/低 (L)/无 (N)N

1.1.2 补充指标

名称指标默认
安全 (S)未定义 (X)/可忽略的 (N)/存在的 §X
自动化 (AU)未定义 (X)/否(N)/是 (Y)X
恢复性 ®未定义 (X)/自动的 (A)/用户 (U)/不可恢复 (I)X
价值密度 (V)未定义 (X)/分散性 (D)/集中性 ©X
漏洞响应工作 (RE)未定义 (X)/低 (L)/中 (M)/高 (H)X
供应商紧急性 (U)未定义 (X)/无(Clear)/低(Green)/中(Amber)/高(Red)X

1.1.3 环境-修改的基本指标

1.1.3.1 可利用性指标
名称指标默认
攻击向量 (MAV)未定义 (X)/网络 (N)/相邻 (A)/本地 (L)/物理 §X
攻击复杂度 (MAC)未定义 (X)/低 (L)/高 (H)X
攻击要求 (MAT)未定义 (X)/无 (N)/存在 §X
所需权限 (MPR)未定义 (X)/无 (N)/低 (L)/高 (H)X
用户交互 (MUI)未定义 (X)/None (N)/Passive §/Active (A)X
1.1.3.2 易受攻击系统影响指标
名称指标默认
机密性 (MVC)未定义 (X)/高 (H)/低 (L)/无 (N)X
完整性 (MVI)未定义 (X)/高 (H)/低 (L)/无 (N)X
可用性 (MVA)未定义 (X)/高 (H)/低 (L)/无 (N)X
1.1.3.3 后续系统影响性
名称指标默认
机密性 (MSC)未定义 (X)/高 (H)/低 (L)/可忽略 (N)X
完整性 (MSI)未定义 (X)/安全 (S)/高 (H)/低 (L)/可忽略 (N)X
可用性 (MSA)未定义 (X)/安全 (S)/高 (H)/低 (L)/可忽略 (N)X

1.1.4 环境-安全要求

名称指标默认
机密要求 (CR)未定义 (X)/高 (H)/中 (M)/低 (L)X
完整性要求 (IR)未定义 (X)/高 (H)/中 (M)/低 (L)X
可用性要求 (AR)未定义 (X)/高 (H)/中 (M)/低 (L)X

1.1.5 威胁指标

名称指标默认
利用情报 (E)未定义 (X)/在野利用 (A)/概念验证 §/无报告 (U)X

1.2.基本指标、威胁指标、环境和补充指标–

CVSS-BTE分数 = 基础 MacroVector 分数 - (基础分数 - 相邻低分)×(指标距离 / 组内最大距离)

1.2.1.确定等价类(EQ)级别

将指标分为 6 个等价类,每个 EQ 对应不同的指标组合,其级别由指标值决定:
EQ1:Attack Vector (AV)-攻击向量、Privileges Required (PR)-所需权限要求、User Interaction (UI)-用户交互
EQ2:Attack Complexity (AC)-攻击复杂性、Attack Requirements (AT)-攻击要求
EQ3:Vulnerable System Confidentiality (VC)-易受攻击系统的机(保)密性影响、Integrity (VI)-易受攻击系统的完整性影响、Availability (VA)-易受攻击系统的可用性影响
EQ4:Subsequent System Confidentiality (SC)-后续系统的机(保)密性影响、Integrity (SI)-后续系统的完整性影响、Availability (SA)-后续系统的可用性影响,以及 Safety (S)-安全性
EQ5:Exploit Maturity (E)-威胁指标利用成熟度
EQ6:VC/VI/VA 与 Confidentiality Requirement (CR)-机(保)密性、Integrity Requirement (IR)-完整性、Availability Requirement (AR)-可用性 的组合(+的关系)

1.2.2.确定 MacroVector 及其基础分数

每个 MacroVector 由各 EQ 的级别组合定义,其基础分数通过专家评估预先确定,存储在 cvss_lookup.js 文件中
通过各 EQ 的级别组合,确定向量所属的 MacroVector(等价类集合)
一般通过 cvss_lookup 查询获取

1.2.3.计算指标距离与分数调整

对于目标向量,计算其与所在 MacroVector 中最高严重性向量的 严重性距离(Severity Distance),即通过改变单个指标值使其转化为最高严重性向量所需的步骤数。

1.2.4. 计算最终分数

步骤 1:确定 MacroVector 的基础分数 S_macro。
步骤 2:计算目标向量在 MacroVector 内的深度 D(即该 MacroVector 中最高与最低向量的最大距离)。
步骤 3:计算目标向量与最高向量的距离 d。
步骤 4:计算调整因子 f = d / D,若 D=0(无距离),则 f=0。
步骤 5:最终分数 S = S_macro - (S_macro - S_lower) × f,其中 S_lower 为相邻较低 MacroVector 的分数,若无则忽略。
步骤 6:分数四舍五入到一位小数。

1.3.计算逻辑

1.3.1 以go语言为例:

1.3.1.1. 首先会获取到一个选中的cvss4的评分向量,

如:CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N
暂定变量VectorString,代码:

VectorString :="CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N"
1.3.1.2. 由于CVSS4的指标一共有31个,

这里需要判断评分向量数据是否异常,且补充默认项

定义所有默认项:

var allCvssSelected = map[string]string{"AC": "L", "AR": "X", "AT": "N", "AU": "X", "AV": "N", "CR": "X", "E": "X", "IR": "X", "MAC": "X", "MAT": "X", "MAV": "X", "MPR": "X", "MSA": "X", "MSC": "X", "MSI": "X", "MUI": "X", "MVA": "X", "MVC": "X", "MVI": "X", "PR": "N", "R": "X", "RE": "X", "S": "X", "SA": "N", "SC": "N", "SI": "N", "U": "X", "UI": "N", "V": "X", "VA": "N", "VC": "N", "VI": "N"}

这里要判断VectorString的数据正确,然后替换到默认项allCvssSelected,如

cvssSelected:=GetCvssSelected(VectorString)

具体GetCvssSelected实现很简单,参考坐标### 1.1.1 基本指标,这里需要定义一个包含31个指标的Map用于校验key和value;如:

var ExpectedMetricOrder = map[string][]string{
    // 基础指标组 (11 个指标)
    "AV": {"N", "A", "L", "P"}, // Attack Vector
    "AC": {"L", "H"},           // Attack Complexity
    "AT": {"N", "P"},           // Attack Requirements
    "PR": {"N", "L", "H"},      // Privileges Required
    "UI": {"N", "P", "A"},      // User Interaction
    "VC": {"H", "L", "N"},      // Confidentiality Impact
    "VI": {"H", "L", "N"},      // Integrity Impact
    "VA": {"H", "L", "N"},      // Availability Impact
    "SC": {"H", "L", "N"},      // Confidentiality Requirement
    "SI": {"H", "L", "N"},      // Integrity Requirement
    "SA": {"H", "L", "N"},      // Availability Requirement
    // 威胁指标组 (1 个指标)
    "E": {"X", "A", "P", "U"}, // Exploit Code Maturity
    // 环境指标组 (14 个指标)
    "CR":  {"X", "H", "M", "L"},      // Confidentiality Requirement
    "IR":  {"X", "H", "M", "L"},      // Integrity Requirement
    "AR":  {"X", "H", "M", "L"},      // Availability Requirement
    "MAV": {"X", "N", "A", "L", "P"}, // Modified Attack Vector
    "MAC": {"X", "L", "H"},           // Modified Attack Complexity
    "MAT": {"X", "N", "P"},           // Modified Attack Requirements
    "MPR": {"X", "N", "L", "H"},      // Modified Privileges Required
    "MUI": {"X", "N", "P", "A"},      // Modified User Interaction
    "MVC": {"X", "H", "L", "N"},      // Modified Confidentiality Impact
    "MVI": {"X", "H", "L", "N"},      // Modified Integrity Impact
    "MVA": {"X", "H", "L", "N"},      // Modified Availability Impact
    "MSC": {"X", "H", "L", "N"},      // Modified Confidentiality Requirement
    "MSI": {"X", "S", "H", "L", "N"}, // Modified Integrity Requirement
    "MSA": {"X", "S", "H", "L", "N"}, // Modified Availability Requirement
    // 补充指标组 (6 个指标)
    "S":  {"X", "N", "P"},                         // Security Requirements
    "AU": {"X", "N", "Y"},                         // Authentication
    "R":  {"X", "A", "U", "I"},                    // Remediation Level
    "V":  {"X", "D", "C"},                         // Report Confidence
    "RE": {"X", "L", "M", "H"},                    // Vulnerability Response Effort
    "U":  {"X", "Clear", "Green", "Amber", "Red"}, // User Notes
    }

具体判断和覆盖默认值逻辑实现,常规判断自己处理好

func GetCvssSelected(vector string) (map[string]string, error) {
	if len(vector) > 0 && vector[0] == '#' {
		vector = vector[1:]
	}
	if !strings.HasPrefix(vector, "CVSS:4.0") {
		return nil, fmt.Errorf("invalid vector, missing CVSS:4.0 prefix")
	}
	metrics := strings.Split(vector, "/")
	if len(metrics) < 2 {
		return nil, fmt.Errorf("invalid vector format after splitting")
	}
	metrics = metrics[1:]
	toSelect := make(map[string]string, len(metrics))
	for _, metricStr := range metrics {
		parts := strings.Split(metricStr, ":")
		if len(parts) != 2 {
			return nil, fmt.Errorf("invalid metric format: %s", metricStr)
		}
		key, value := parts[0], parts[1]
		expected, ok := ExpectedMetricOrder[key]
		if !ok || expected == nil {
			return nil, fmt.Errorf("invalid vector, unexpected metric key: %s", key)
		}
		expectedMap := make(map[string]bool, len(expected))
		for _, v := range expected {
			expectedMap[v] = true
		}
		if !expectedMap[value] {
			return nil, fmt.Errorf("invalid vector, for key %s, value is invalid", key)
		}
		toSelect[key] = value
	}
	reSelect := allCvssSelected
	for kt, vt := range toSelect {
		reSelect[kt] = vt
	}
	return reSelect, nil
}
1.3.1.3. MacroVector 分数查找表,一般定义为CvssLookup
var CvssLookup = map[string]float64{"000000": 10, "000001": 9.9, "000010": 9.8, "000011": 9.5, "000020": 9.5, "000021": 9.2, "000100": 10, "000101": 9.6, "000110": 9.3, "000111": 8.7, "000120": 9.1, "000121": 8.1, "000200": 9.3, "000201": 9, "000210": 8.9, "000211": 8, "000220": 8.1, "000221": 6.8, "001000": 9.8, "001001": 9.5, "001010": 9.5, "001011": 9.2, "001020": 9, "001021": 8.4, "001100": 9.3, "001101": 9.2, "001110": 8.9, "001111": 8.1, "001120": 8.1, "001121": 6.5, "001200": 8.8, "001201": 8, "001210": 7.8, "001211": 7, "001220": 6.9, "001221": 4.8, "002001": 9.2, "002011": 8.2, "002021": 7.2, "002101": 7.9, "002111": 6.9, "002121": 5, "002201": 6.9, "002211": 5.5, "002221": 2.7, "010000": 9.9, "010001": 9.7, "010010": 9.5, "010011": 9.2, "010020": 9.2, "010021": 8.5, "010100": 9.5, "010101": 9.1, "010110": 9, "010111": 8.3, "010120": 8.4, "010121": 7.1, "010200": 9.2, "010201": 8.1, "010210": 8.2, "010211": 7.1, "010220": 7.2, "010221": 5.3, "011000": 9.5, "011001": 9.3, "011010": 9.2, "011011": 8.5, "011020": 8.5, "011021": 7.3, "011100": 9.2, "011101": 8.2, "011110": 8, "011111": 7.2, "011120": 7, "011121": 5.9, "011200": 8.4, "011201": 7, "011210": 7.1, "011211": 5.2, "011220": 5, "011221": 3, "012001": 8.6, "012011": 7.5, "012021": 5.2, "012101": 7.1, "012111": 5.2, "012121": 2.9, "012201": 6.3, "012211": 2.9, "012221": 1.7, "100000": 9.8, "100001": 9.5, "100010": 9.4, "100011": 8.7, "100020": 9.1, "100021": 8.1, "100100": 9.4, "100101": 8.9, "100110": 8.6, "100111": 7.4, "100120": 7.7, "100121": 6.4, "100200": 8.7, "100201": 7.5, "100210": 7.4, "100211": 6.3, "100220": 6.3, "100221": 4.9, "101000": 9.4, "101001": 8.9, "101010": 8.8, "101011": 7.7, "101020": 7.6, "101021": 6.7, "101100": 8.6, "101101": 7.6, "101110": 7.4, "101111": 5.8, "101120": 5.9, "101121": 5, "101200": 7.2, "101201": 5.7, "101210": 5.7, "101211": 5.2, "101220": 5.2, "101221": 2.5, "102001": 8.3, "102011": 7, "102021": 5.4, "102101": 6.5, "102111": 5.8, "102121": 2.6, "102201": 5.3, "102211": 2.1, "102221": 1.3, "110000": 9.5, "110001": 9, "110010": 8.8, "110011": 7.6, "110020": 7.6, "110021": 7, "110100": 9, "110101": 7.7, "110110": 7.5, "110111": 6.2, "110120": 6.1, "110121": 5.3, "110200": 7.7, "110201": 6.6, "110210": 6.8, "110211": 5.9, "110220": 5.2, "110221": 3, "111000": 8.9, "111001": 7.8, "111010": 7.6, "111011": 6.7, "111020": 6.2, "111021": 5.8, "111100": 7.4, "111101": 5.9, "111110": 5.7, "111111": 5.7, "111120": 4.7, "111121": 2.3, "111200": 6.1, "111201": 5.2, "111210": 5.7, "111211": 2.9, "111220": 2.4, "111221": 1.6, "112001": 7.1, "112011": 5.9, "112021": 3, "112101": 5.8, "112111": 2.6, "112121": 1.5, "112201": 2.3, "112211": 1.3, "112221": 0.6, "200000": 9.3, "200001": 8.7, "200010": 8.6, "200011": 7.2, "200020": 7.5, "200021": 5.8, "200100": 8.6, "200101": 7.4, "200110": 7.4, "200111": 6.1, "200120": 5.6, "200121": 3.4, "200200": 7, "200201": 5.4, "200210": 5.2, "200211": 4, "200220": 4, "200221": 2.2, "201000": 8.5, "201001": 7.5, "201010": 7.4, "201011": 5.5, "201020": 6.2, "201021": 5.1, "201100": 7.2, "201101": 5.7, "201110": 5.5, "201111": 4.1, "201120": 4.6, "201121": 1.9, "201200": 5.3, "201201": 3.6, "201210": 3.4, "201211": 1.9, "201220": 1.9, "201221": 0.8, "202001": 6.4, "202011": 5.1, "202021": 2, "202101": 4.7, "202111": 2.1, "202121": 1.1, "202201": 2.4, "202211": 0.9, "202221": 0.4, "210000": 8.8, "210001": 7.5, "210010": 7.3, "210011": 5.3, "210020": 6, "210021": 5, "210100": 7.3, "210101": 5.5, "210110": 5.9, "210111": 4, "210120": 4.1, "210121": 2, "210200": 5.4, "210201": 4.3, "210210": 4.5, "210211": 2.2, "210220": 2, "210221": 1.1, "211000": 7.5, "211001": 5.5, "211010": 5.8, "211011": 4.5, "211020": 4, "211021": 2.1, "211100": 6.1, "211101": 5.1, "211110": 4.8, "211111": 1.8, "211120": 2, "211121": 0.9, "211200": 4.6, "211201": 1.8, "211210": 1.7, "211211": 0.7, "211220": 0.8, "211221": 0.2, "212001": 5.3, "212011": 2.4, "212021": 1.4, "212101": 2.4, "212111": 1.2, "212121": 0.5, "212201": 1, "212211": 0.3, "212221": 0.1}

1.3 最终实现CVSS评分方法

func CalculateScore(VectorString string) float64 {
	cvssSelected, _ := GetCvssSelected(VectorString)
	impactMetrics := []string{"VC", "VI", "VA", "SC", "SI", "SA"}
	allN := true
	for _, metric := range impactMetrics {
		if M(cvssSelected, metric) != "N" {
			allN = false
			break
		}
	}
	if allN {
		return 0.0
	}

	macroVectorResult := MacroVector(cvssSelected)
	if len(macroVectorResult) != 6 {
		return 0.0
	}
	value := CvssLookup[macroVectorResult]
	chars := strings.Split(macroVectorResult, "")
	eq1, _ := strconv.Atoi(chars[0])
	eq2, _ := strconv.Atoi(chars[1])
	eq3, _ := strconv.Atoi(chars[2])
	eq4, _ := strconv.Atoi(chars[3])
	eq5, _ := strconv.Atoi(chars[4])
	eq6, _ := strconv.Atoi(chars[5])
	eq1NextLowerMacro := fmt.Sprintf("%d%d%d%d%d%d", eq1+1, eq2, eq3, eq4, eq5, eq6)
	eq2NextLowerMacro := fmt.Sprintf("%d%d%d%d%d%d", eq1, eq2+1, eq3, eq4, eq5, eq6)
	var eq3eq6NextLowerMacro string
	if eq3 == 1 && eq6 == 1 {
		eq3eq6NextLowerMacro = fmt.Sprintf("%d%d%d%d%d%d", eq1, eq2, eq3+1, eq4, eq5, eq6)
	} else if eq3 == 0 && eq6 == 1 {
		eq3eq6NextLowerMacro = fmt.Sprintf("%d%d%d%d%d%d", eq1, eq2, eq3+1, eq4, eq5, eq6)
	} else if eq3 == 1 && eq6 == 0 {
		eq3eq6NextLowerMacro = fmt.Sprintf("%d%d%d%d%d%d", eq1, eq2, eq3, eq4, eq5, eq6+1)
	} else if eq3 == 0 && eq6 == 0 {
		left := fmt.Sprintf("%d%d%d%d%d%d", eq1, eq2, eq3, eq4, eq5, eq6+1)
		right := fmt.Sprintf("%d%d%d%d%d%d", eq1, eq2, eq3+1, eq4, eq5, eq6)
		scoreLeft := CvssLookup[left]
		scoreRight := CvssLookup[right]
		if scoreLeft > scoreRight {
			eq3eq6NextLowerMacro = left
		} else {
			eq3eq6NextLowerMacro = right
		}
	} else {
		eq3eq6NextLowerMacro = fmt.Sprintf("%d%d%d%d%d%d", eq1, eq2, eq3+1, eq4, eq5, eq6+1)
	}
	eq4NextLowerMacro := fmt.Sprintf("%d%d%d%d%d%d", eq1, eq2, eq3, eq4+1, eq5, eq6)
	eq5NextLowerMacro := fmt.Sprintf("%d%d%d%d%d%d", eq1, eq2, eq3, eq4, eq5+1, eq6)
	scoreEq1NextLowerMacro := CvssLookup[eq1NextLowerMacro]
	scoreEq2NextLowerMacro := CvssLookup[eq2NextLowerMacro]
	scoreEq3eq6NextLowerMacro := CvssLookup[eq3eq6NextLowerMacro]
	scoreEq4NextLowerMacro := CvssLookup[eq4NextLowerMacro]
	scoreEq5NextLowerMacro := CvssLookup[eq5NextLowerMacro]
	eq1Maxes := getEQMaxes(1, eq1)
	eq2Maxes := getEQMaxes(2, eq2)
	eq3eq6Maxes := getEQMaxes3(eq3, eq6)
	eq4Maxes := getEQMaxes(4, eq4)
	eq5Maxes := getEQMaxes(5, eq5)
	maxVectors := make([]string, 0)
	for _, eq1Max := range eq1Maxes {
		for _, eq2Max := range eq2Maxes {
			for _, eq3eq6Max := range eq3eq6Maxes {
				for _, eq4Max := range eq4Maxes {
					for _, eq5Max := range eq5Maxes {
						maxVectors = append(maxVectors, fmt.Sprintf("%s%s%s%s%s",
							eq1Max, eq2Max, eq3eq6Max, eq4Max, eq5Max))
					}
				}
			}
		}
	}
	var maxVector string
	var severityDistanceAV, severityDistancePR, severityDistanceUI,
		severityDistanceAC, severityDistanceAT,
		severityDistanceVC, severityDistanceVI, severityDistanceVA,
		severityDistanceSC, severityDistanceSI, severityDistanceSA,
		severityDistanceCR, severityDistanceIR, severityDistanceAR float64
	for _, mv := range maxVectors {
		severityDistanceAV = AVLevels[M(cvssSelected, "AV")] - AVLevels[ExtractValueMetric("AV", mv)]
		severityDistancePR = PRLevels[M(cvssSelected, "PR")] - PRLevels[ExtractValueMetric("PR", mv)]
		severityDistanceUI = UILevels[M(cvssSelected, "UI")] - UILevels[ExtractValueMetric("UI", mv)]
		severityDistanceAC = ACLevels[M(cvssSelected, "AC")] - ACLevels[ExtractValueMetric("AC", mv)]
		severityDistanceAT = ATLevels[M(cvssSelected, "AT")] - ATLevels[ExtractValueMetric("AT", mv)]
		severityDistanceVC = VCLevels[M(cvssSelected, "VC")] - VCLevels[ExtractValueMetric("VC", mv)]
		severityDistanceVI = VILevels[M(cvssSelected, "VI")] - VILevels[ExtractValueMetric("VI", mv)]
		severityDistanceVA = VALevels[M(cvssSelected, "VA")] - VALevels[ExtractValueMetric("VA", mv)]
		severityDistanceSC = SCLevels[M(cvssSelected, "SC")] - SCLevels[ExtractValueMetric("SC", mv)]
		severityDistanceSI = SILevels[M(cvssSelected, "SI")] - SILevels[ExtractValueMetric("SI", mv)]
		severityDistanceSA = SALevels[M(cvssSelected, "SA")] - SALevels[ExtractValueMetric("SA", mv)]
		severityDistanceCR = CRLevels[M(cvssSelected, "CR")] - CRLevels[ExtractValueMetric("CR", mv)]
		severityDistanceIR = IRLevels[M(cvssSelected, "IR")] - IRLevels[ExtractValueMetric("IR", mv)]
		severityDistanceAR = ARLevels[M(cvssSelected, "AR")] - ARLevels[ExtractValueMetric("AR", mv)]
		if severityDistanceAV < 0 || severityDistancePR < 0 || severityDistanceUI < 0 ||
			severityDistanceAC < 0 || severityDistanceAT < 0 || severityDistanceVC < 0 ||
			severityDistanceVI < 0 || severityDistanceVA < 0 || severityDistanceSC < 0 ||
			severityDistanceSI < 0 || severityDistanceSA < 0 || severityDistanceCR < 0 ||
			severityDistanceIR < 0 || severityDistanceAR < 0 {
			continue
		}
		maxVector = mv
		break
	}
	if maxVector == "" {
		return math.Round(value*10) / 10
	}
	currentSeverityDistanceEq1 := severityDistanceAV + severityDistancePR + severityDistanceUI
	currentSeverityDistanceEq2 := severityDistanceAC + severityDistanceAT
	currentSeverityDistanceEq3eq6 := severityDistanceVC + severityDistanceVI + severityDistanceVA + severityDistanceCR + severityDistanceIR + severityDistanceAR
	currentSeverityDistanceEq4 := severityDistanceSC + severityDistanceSI + severityDistanceSA
	step := 0.1
	var availableDistanceEq1 float64
	if scoreEq1NextLowerMacro != 0 {
		availableDistanceEq1 = value - scoreEq1NextLowerMacro
	}
	var availableDistanceEq2 float64
	if scoreEq2NextLowerMacro != 0 {
		availableDistanceEq2 = value - scoreEq2NextLowerMacro
	}
	var availableDistanceEq3eq6 float64
	if scoreEq3eq6NextLowerMacro != 0 {
		availableDistanceEq3eq6 = value - scoreEq3eq6NextLowerMacro
	}
	var availableDistanceEq4 float64
	if scoreEq4NextLowerMacro != 0 {
		availableDistanceEq4 = value - scoreEq4NextLowerMacro
	}
	var availableDistanceEq5 float64
	if scoreEq5NextLowerMacro != 0 {
		availableDistanceEq5 = value - scoreEq5NextLowerMacro
	}
	percentToNextEq1Severity := 0.0
	percentToNextEq2Severity := 0.0
	percentToNextEq3eq6Severity := 0.0
	percentToNextEq4Severity := 0.0
	percentToNextEq5Severity := 0.0
	normalizedSeverityEq1 := 0.0
	normalizedSeverityEq2 := 0.0
	normalizedSeverityEq3eq6 := 0.0
	normalizedSeverityEq4 := 0.0
	normalizedSeverityEq5 := 0.0
	getMaxSeverity := func(eq string, value int, eq6value int) float64 {
		result := NewMaxSeverity()
		var eqN map[int]float64
		if eq == "EQ1" {
			eqN = result.EQ1
		} else if eq == "EQ2" {
			eqN = result.EQ2
		} else if eq == "EQ3EQ6" {
			base := result.EQ3EQ6
			eqN = base[value]
			value = eq6value
		} else if eq == "EQ4" {
			eqN = result.EQ4
		}
		num, ok := eqN[value]
		if ok {
			return num
		}
		return 0.0
	}
	maxSeverityEq1 := getMaxSeverity("EQ1", eq1, 0) * step
	maxSeverityEq2 := getMaxSeverity("EQ2", eq2, 0) * step
	maxSeverityEq3eq6 := getMaxSeverity("EQ3EQ6", eq3, eq6) * step
	maxSeverityEq4 := getMaxSeverity("EQ4", eq4, 0) * step
	nExistingLower := 0
	if availableDistanceEq1 != 0 {
		nExistingLower++
		percentToNextEq1Severity = currentSeverityDistanceEq1 / maxSeverityEq1
		normalizedSeverityEq1 = availableDistanceEq1 * percentToNextEq1Severity
	}
	if availableDistanceEq2 != 0 {
		nExistingLower++
		percentToNextEq2Severity = currentSeverityDistanceEq2 / maxSeverityEq2
		normalizedSeverityEq2 = availableDistanceEq2 * percentToNextEq2Severity
	}
	if availableDistanceEq3eq6 != 0 {
		nExistingLower++
		percentToNextEq3eq6Severity = currentSeverityDistanceEq3eq6 / maxSeverityEq3eq6
		normalizedSeverityEq3eq6 = availableDistanceEq3eq6 * percentToNextEq3eq6Severity
	}
	if availableDistanceEq4 != 0 {
		nExistingLower++
		percentToNextEq4Severity = currentSeverityDistanceEq4 / maxSeverityEq4
		normalizedSeverityEq4 = availableDistanceEq4 * percentToNextEq4Severity
	}
	if availableDistanceEq5 != 0 {
		nExistingLower++
		percentToNextEq5Severity = 0.0
		normalizedSeverityEq5 = availableDistanceEq5 * percentToNextEq5Severity
	}
	totalNormalizedSeverity := normalizedSeverityEq1 + normalizedSeverityEq2 + normalizedSeverityEq3eq6 + normalizedSeverityEq4 + normalizedSeverityEq5
	var meanDistance float64
	if nExistingLower == 0 {
		meanDistance = 0
	} else {
		meanDistance = totalNormalizedSeverity / float64(nExistingLower)
	}
	value -= meanDistance
	if value < 0 {
		value = 0.0
	}
	if value > 10 {
		value = 10.0
	}
	return math.Round(value*10) / 10
}

预期结构测试用例:

func main() {
	VectorString := "CVSS:4.0/AV:A/AC:H/AT:P/PR:L/UI:P/VC:L/VI:L/VA:L/SC:L/SI:L/SA:L/E:A/CR:M/IR:M/AR:M/MAV:A/MAC:H/MAT:P/MPR:L/MUI:P/MVC:L/MVI:L/MVA:L/MSC:H/MSI:H/MSA:H/S:P" //2.4
	VectorString = "CVSS:4.0/AV:A/AC:H/AT:P/PR:L/UI:P/VC:L/VI:L/VA:L/SC:H/SI:L/SA:L/E:X/S:N/AU:N/R:A/V:D/RE:L/U:Clear"                                                         //2.1
	score :=  CalculateScore(VectorString)
	fmt.Println(score)
	level :=  QualScore(score)
	fmt.Println(level)
}

在这里插入图片描述
在这里插入图片描述

整体实现go代码可联系我

1.4 js和文档参考链接:

https://www.first.org/cvss/calculator/4-0
https://cvss.xc1ym.com/app.js?v=7

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐