Skip to content

向量解析示例

本示例演示了各种解析 CVSS 向量字符串的方法,包括不同格式、错误处理和验证技术。

概述

CVSS Parser 支持解析各种格式和配置的 CVSS 3.0 和 3.1 向量字符串。本指南涵盖:

  • 基本向量解析
  • 不同向量格式
  • 错误处理和验证
  • 批量解析
  • 性能优化

基本向量解析

简单解析

go
package main

import (
    "fmt"
    "log"

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

func main() {
    // 基本 CVSS 3.1 向量
    vectorStr := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
    
    // 创建解析器
    p := parser.NewCvss3xParser(vectorStr)
    
    // 解析向量
    vector, err := p.Parse()
    if err != nil {
        log.Fatalf("解析失败: %v", err)
    }
    
    fmt.Printf("解析成功: %s\n", vector.String())
    fmt.Printf("版本: %d.%d\n", vector.MajorVersion, vector.MinorVersion)
}

解析不同 CVSS 版本

go
func parseMultipleVersions() {
    vectors := map[string]string{
        "CVSS 3.0": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
        "CVSS 3.1": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
    }
    
    for version, vectorStr := range vectors {
        fmt.Printf("\n--- 解析 %s ---\n", version)
        
        parser := parser.NewCvss3xParser(vectorStr)
        vector, err := parser.Parse()
        if err != nil {
            fmt.Printf("错误: %v\n", err)
            continue
        }
        
        fmt.Printf("向量: %s\n", vectorStr)
        fmt.Printf("解析版本: %d.%d\n", vector.MajorVersion, vector.MinorVersion)
        fmt.Printf("有效: %t\n", vector.IsValid())
    }
}

向量格式变化

仅基础指标

go
func parseBaseOnly() {
    // 最小必需的基础指标
    baseVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
    
    parser := parser.NewCvss3xParser(baseVector)
    vector, err := parser.Parse()
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("基础向量: %s\n", vector.String())
    fmt.Printf("包含时间指标: %t\n", vector.HasTemporal())
    fmt.Printf("包含环境指标: %t\n", vector.HasEnvironmental())
}

带时间指标的向量

go
func parseWithTemporal() {
    // 带时间指标的向量
    temporalVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/E:F/RL:O/RC:C"
    
    parser := parser.NewCvss3xParser(temporalVector)
    vector, err := parser.Parse()
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("时间向量: %s\n", vector.String())
    fmt.Printf("包含时间指标: %t\n", vector.HasTemporal())
    
    if vector.HasTemporal() {
        fmt.Printf("漏洞利用代码成熟度: %s\n", 
            vector.Cvss3xTemporal.ExploitCodeMaturity.GetLongValue())
        fmt.Printf("修复级别: %s\n", 
            vector.Cvss3xTemporal.RemediationLevel.GetLongValue())
        fmt.Printf("报告可信度: %s\n", 
            vector.Cvss3xTemporal.ReportConfidence.GetLongValue())
    }
}

带环境指标的向量

go
func parseWithEnvironmental() {
    // 带环境指标的向量
    envVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/CR:H/IR:H/AR:H/MAV:L/MAC:H/MPR:H/MUI:R/MS:C/MC:H/MI:H/MA:H"
    
    parser := parser.NewCvss3xParser(envVector)
    vector, err := parser.Parse()
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("环境向量: %s\n", vector.String())
    fmt.Printf("包含环境指标: %t\n", vector.HasEnvironmental())
    
    if vector.HasEnvironmental() {
        fmt.Printf("机密性需求: %s\n", 
            vector.Cvss3xEnvironmental.ConfidentialityRequirement.GetLongValue())
        fmt.Printf("修改的攻击向量: %s\n", 
            vector.Cvss3xEnvironmental.ModifiedAttackVector.GetLongValue())
    }
}

包含所有指标的完整向量

go
func parseCompleteVector() {
    // 包含基础、时间和环境指标的完整向量
    completeVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/E:F/RL:O/RC:C/CR:H/IR:H/AR:H/MAV:L/MAC:H/MPR:H/MUI:R/MS:C/MC:H/MI:H/MA:H"
    
    parser := parser.NewCvss3xParser(completeVector)
    vector, err := parser.Parse()
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("完整向量: %s\n", vector.String())
    fmt.Printf("包含时间指标: %t\n", vector.HasTemporal())
    fmt.Printf("包含环境指标: %t\n", vector.HasEnvironmental())
    fmt.Printf("总指标数: %d\n", countMetrics(vector))
}

func countMetrics(vector *cvss.Cvss3x) int {
    count := 8 // 基础指标
    if vector.HasTemporal() {
        count += 3 // 时间指标
    }
    if vector.HasEnvironmental() {
        count += 11 // 环境指标
    }
    return count
}

错误处理和验证

健壮的解析与错误处理

go
func robustParsing(vectorStr string) (*cvss.Cvss3x, error) {
    // 输入验证
    if vectorStr == "" {
        return nil, fmt.Errorf("向量字符串不能为空")
    }
    
    if len(vectorStr) > 200 {
        return nil, fmt.Errorf("向量字符串过长: %d 字符", len(vectorStr))
    }
    
    if !strings.HasPrefix(vectorStr, "CVSS:") {
        return nil, fmt.Errorf("无效的向量格式: 必须以 'CVSS:' 开头")
    }
    
    // 带错误处理的解析
    parser := parser.NewCvss3xParser(vectorStr)
    vector, err := parser.Parse()
    if err != nil {
        return nil, fmt.Errorf("解析失败: %w", err)
    }
    
    // 解析后验证
    if !vector.IsValid() {
        return nil, fmt.Errorf("解析的向量无效")
    }
    
    return vector, nil
}

处理不同错误类型

go
func handleParseErrors(vectorStr string) {
    parser := parser.NewCvss3xParser(vectorStr)
    vector, err := parser.Parse()
    
    if err != nil {
        switch e := err.(type) {
        case *parser.ParseError:
            fmt.Printf("解析错误: %s\n", e.Message)
            fmt.Printf("位置: %d\n", e.Position)
            fmt.Printf("输入: %s\n", e.Input)
        case *parser.ValidationError:
            fmt.Printf("验证错误: %s\n", e.Message)
            fmt.Printf("指标: %s\n", e.Metric)
            fmt.Printf("值: %s\n", e.Value)
        default:
            fmt.Printf("未知错误: %v\n", err)
        }
        return
    }
    
    fmt.Printf("解析成功: %s\n", vector.String())
}

验证示例

go
func validateVector(vector *cvss.Cvss3x) []string {
    var issues []string
    
    // 检查版本
    if vector.MajorVersion != 3 {
        issues = append(issues, fmt.Sprintf("不支持的主版本: %d", vector.MajorVersion))
    }
    
    if vector.MinorVersion != 0 && vector.MinorVersion != 1 {
        issues = append(issues, fmt.Sprintf("不支持的次版本: %d", vector.MinorVersion))
    }
    
    // 检查基础指标
    if vector.Cvss3xBase == nil {
        issues = append(issues, "缺少基础指标")
    } else {
        if vector.Cvss3xBase.AttackVector == nil {
            issues = append(issues, "缺少攻击向量")
        }
        if vector.Cvss3xBase.AttackComplexity == nil {
            issues = append(issues, "缺少攻击复杂度")
        }
        // ... 检查其他必需指标
    }
    
    return issues
}

批量解析

处理多个向量

go
func batchParsing(vectors []string) []ParseResult {
    results := make([]ParseResult, len(vectors))
    
    for i, vectorStr := range vectors {
        result := ParseResult{
            Input: vectorStr,
            Index: i,
        }
        
        vector, err := robustParsing(vectorStr)
        if err != nil {
            result.Error = err
        } else {
            result.Vector = vector
            result.Success = true
        }
        
        results[i] = result
    }
    
    return results
}

type ParseResult struct {
    Input   string
    Index   int
    Vector  *cvss.Cvss3x
    Success bool
    Error   error
}

func (r ParseResult) String() string {
    if r.Success {
        return fmt.Sprintf("[%d] 成功: %s", r.Index, r.Input)
    }
    return fmt.Sprintf("[%d] 错误: %s - %v", r.Index, r.Input, r.Error)
}

并发批量处理

go
func concurrentBatchParsing(vectors []string) []ParseResult {
    results := make([]ParseResult, len(vectors))
    var wg sync.WaitGroup
    
    for i, vectorStr := range vectors {
        wg.Add(1)
        go func(index int, vector string) {
            defer wg.Done()
            
            result := ParseResult{
                Input: vector,
                Index: index,
            }
            
            parsed, err := robustParsing(vector)
            if err != nil {
                result.Error = err
            } else {
                result.Vector = parsed
                result.Success = true
            }
            
            results[index] = result
        }(i, vectorStr)
    }
    
    wg.Wait()
    return results
}

带统计信息的批量处理

go
func batchParsingWithStats(vectors []string) BatchStats {
    results := batchParsing(vectors)
    
    stats := BatchStats{
        Total:   len(vectors),
        Results: results,
    }
    
    for _, result := range results {
        if result.Success {
            stats.Successful++
        } else {
            stats.Failed++
            stats.Errors = append(stats.Errors, result.Error)
        }
    }
    
    return stats
}

type BatchStats struct {
    Total      int
    Successful int
    Failed     int
    Results    []ParseResult
    Errors     []error
}

func (s BatchStats) SuccessRate() float64 {
    if s.Total == 0 {
        return 0
    }
    return float64(s.Successful) / float64(s.Total) * 100
}

func (s BatchStats) Print() {
    fmt.Printf("批量处理统计:\n")
    fmt.Printf("  总向量数: %d\n", s.Total)
    fmt.Printf("  成功: %d\n", s.Successful)
    fmt.Printf("  失败: %d\n", s.Failed)
    fmt.Printf("  成功率: %.1f%%\n", s.SuccessRate())
    
    if len(s.Errors) > 0 {
        fmt.Printf("  常见错误:\n")
        errorCounts := make(map[string]int)
        for _, err := range s.Errors {
            errorCounts[err.Error()]++
        }
        
        for errMsg, count := range errorCounts {
            fmt.Printf("    %s: %d\n", errMsg, count)
        }
    }
}

性能优化

解析器重用

go
func optimizedParsing(vectors []string) []ParseResult {
    // 重用解析器实例
    parser := parser.NewCvss3xParser("")
    results := make([]ParseResult, len(vectors))
    
    for i, vectorStr := range vectors {
        result := ParseResult{
            Input: vectorStr,
            Index: i,
        }
        
        // 用新向量重用解析器
        parser.SetVector(vectorStr)
        vector, err := parser.Parse()
        
        if err != nil {
            result.Error = err
        } else {
            result.Vector = vector
            result.Success = true
        }
        
        results[i] = result
    }
    
    return results
}

对象池模式

go
var parserPool = sync.Pool{
    New: func() interface{} {
        return parser.NewCvss3xParser("")
    },
}

func parseWithPool(vectorStr string) (*cvss.Cvss3x, error) {
    parser := parserPool.Get().(*parser.Cvss3xParser)
    defer parserPool.Put(parser)
    
    parser.SetVector(vectorStr)
    return parser.Parse()
}

func pooledBatchParsing(vectors []string) []ParseResult {
    results := make([]ParseResult, len(vectors))
    var wg sync.WaitGroup
    
    for i, vectorStr := range vectors {
        wg.Add(1)
        go func(index int, vector string) {
            defer wg.Done()
            
            result := ParseResult{
                Input: vector,
                Index: index,
            }
            
            parsed, err := parseWithPool(vector)
            if err != nil {
                result.Error = err
            } else {
                result.Vector = parsed
                result.Success = true
            }
            
            results[index] = result
        }(i, vectorStr)
    }
    
    wg.Wait()
    return results
}

实际应用示例

文件处理

go
func parseVectorsFromFile(filename string) error {
    file, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer file.Close()
    
    scanner := bufio.NewScanner(file)
    lineNum := 0
    
    for scanner.Scan() {
        lineNum++
        line := strings.TrimSpace(scanner.Text())
        
        if line == "" || strings.HasPrefix(line, "#") {
            continue // 跳过空行和注释
        }
        
        vector, err := robustParsing(line)
        if err != nil {
            fmt.Printf("第 %d 行错误: %v\n", lineNum, err)
            continue
        }
        
        fmt.Printf("第 %d 行: %s -> 有效\n", lineNum, vector.String())
    }
    
    return scanner.Err()
}

CSV 处理

go
func parseVectorsFromCSV(filename string) error {
    file, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer file.Close()
    
    reader := csv.NewReader(file)
    records, err := reader.ReadAll()
    if err != nil {
        return err
    }
    
    for i, record := range records {
        if i == 0 {
            continue // 跳过标题行
        }
        
        if len(record) < 1 {
            continue
        }
        
        vectorStr := record[0]
        vector, err := robustParsing(vectorStr)
        if err != nil {
            fmt.Printf("第 %d 行错误: %v\n", i+1, err)
            continue
        }
        
        fmt.Printf("第 %d 行: %s -> 有效\n", i+1, vector.String())
    }
    
    return nil
}

测试和验证

测试用例

go
func runParsingTests() {
    testCases := []struct {
        name        string
        vector      string
        expectError bool
        description string
    }{
        {
            name:        "有效基础向量",
            vector:      "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
            expectError: false,
            description: "标准高严重性向量",
        },
        {
            name:        "有效时间向量",
            vector:      "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/E:F/RL:O/RC:C",
            expectError: false,
            description: "带时间指标的向量",
        },
        {
            name:        "无效版本",
            vector:      "CVSS:2.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
            expectError: true,
            description: "不支持的 CVSS 版本",
        },
        {
            name:        "缺少指标",
            vector:      "CVSS:3.1/AV:N/AC:L",
            expectError: true,
            description: "不完整的基础指标",
        },
        {
            name:        "无效指标值",
            vector:      "CVSS:3.1/AV:X/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
            expectError: true,
            description: "无效的攻击向量值",
        },
    }
    
    for _, tc := range testCases {
        fmt.Printf("\n--- 测试: %s ---\n", tc.name)
        fmt.Printf("描述: %s\n", tc.description)
        fmt.Printf("向量: %s\n", tc.vector)
        
        vector, err := robustParsing(tc.vector)
        
        if tc.expectError {
            if err != nil {
                fmt.Printf("✓ 预期错误: %v\n", err)
            } else {
                fmt.Printf("✗ 预期错误但解析成功\n")
            }
        } else {
            if err != nil {
                fmt.Printf("✗ 意外错误: %v\n", err)
            } else {
                fmt.Printf("✓ 解析成功: %s\n", vector.String())
            }
        }
    }
}

下一步

掌握向量解析后,您可以探索:

相关文档

Released under the MIT License.