CVE 验证处理
本示例展示如何使用 CVE Utils 实现健壮的 CVE 验证和处理系统,包括用户输入验证、批量数据处理、错误处理和性能优化等最佳实践。
场景描述
作为 Web 应用或 API 开发者,您需要:
- 验证用户输入的 CVE 格式
- 处理各种异常情况和错误
- 实现高性能的批量验证
- 提供友好的错误信息和建议
- 确保系统的稳定性和可靠性
完整示例
1. CVE 验证器
go
package main
import (
"fmt"
"strings"
"time"
"github.com/scagogogo/cve"
)
// ValidationResult 验证结果
type ValidationResult struct {
IsValid bool `json:"is_valid"`
CVE string `json:"cve,omitempty"`
ErrorType string `json:"error_type,omitempty"`
ErrorMsg string `json:"error_message,omitempty"`
Suggestions []string `json:"suggestions,omitempty"`
ProcessTime time.Duration `json:"process_time_ns"`
}
// CVEValidator CVE 验证器
type CVEValidator struct {
strictMode bool
maxYearOffset int
enableSuggestions bool
}
func NewCVEValidator() *CVEValidator {
return &CVEValidator{
strictMode: false,
maxYearOffset: 10,
enableSuggestions: true,
}
}
func (v *CVEValidator) SetStrictMode(strict bool) {
v.strictMode = strict
}
func (v *CVEValidator) SetMaxYearOffset(offset int) {
v.maxYearOffset = offset
}
// ValidateSingle 验证单个 CVE
func (v *CVEValidator) ValidateSingle(input string) ValidationResult {
start := time.Now()
result := ValidationResult{
ProcessTime: time.Since(start),
}
// 基本输入检查
if input == "" {
result.ErrorType = "EMPTY_INPUT"
result.ErrorMsg = "输入不能为空"
result.Suggestions = []string{"请输入有效的 CVE 编号,格式如:CVE-2022-12345"}
return result
}
// 去除前后空格
trimmed := strings.TrimSpace(input)
// 基本格式检查
if !cve.IsCve(trimmed) {
result.ErrorType = "INVALID_FORMAT"
result.ErrorMsg = "CVE 格式无效"
result.Suggestions = v.generateFormatSuggestions(trimmed)
return result
}
// 格式化
formatted := cve.Format(trimmed)
// 严格模式下的额外验证
if v.strictMode {
if !cve.ValidateCve(formatted) {
result.ErrorType = "VALIDATION_FAILED"
result.ErrorMsg = "CVE 验证失败"
result.Suggestions = v.generateValidationSuggestions(formatted)
return result
}
// 年份合理性检查
if !cve.IsCveYearOk(formatted, v.maxYearOffset) {
result.ErrorType = "INVALID_YEAR"
result.ErrorMsg = "CVE 年份不在合理范围内"
result.Suggestions = v.generateYearSuggestions(formatted)
return result
}
}
// 验证成功
result.IsValid = true
result.CVE = formatted
result.ProcessTime = time.Since(start)
return result
}
// generateFormatSuggestions 生成格式建议
func (v *CVEValidator) generateFormatSuggestions(input string) []string {
if !v.enableSuggestions {
return nil
}
var suggestions []string
// 检查是否缺少 CVE 前缀
if strings.Contains(input, "-") && !strings.HasPrefix(strings.ToUpper(input), "CVE-") {
suggestions = append(suggestions, "尝试添加 'CVE-' 前缀:CVE-"+input)
}
// 检查是否有常见的格式错误
if strings.Contains(input, "/") {
fixed := strings.ReplaceAll(input, "/", "-")
suggestions = append(suggestions, "尝试将 '/' 替换为 '-':"+fixed)
}
// 检查是否有空格
if strings.Contains(input, " ") {
fixed := strings.ReplaceAll(input, " ", "-")
suggestions = append(suggestions, "尝试将空格替换为 '-':"+fixed)
}
// 提供标准格式示例
suggestions = append(suggestions, "标准格式示例:CVE-2022-12345")
return suggestions
}
// generateValidationSuggestions 生成验证建议
func (v *CVEValidator) generateValidationSuggestions(cveId string) []string {
if !v.enableSuggestions {
return nil
}
var suggestions []string
year := cve.ExtractCveYearAsInt(cveId)
seq := cve.ExtractCveSeqAsInt(cveId)
currentYear := time.Now().Year()
if year < 1970 {
suggestions = append(suggestions, "年份不能早于 1970 年")
}
if year > currentYear {
suggestions = append(suggestions, fmt.Sprintf("年份不能晚于当前年份 %d", currentYear))
}
if seq <= 0 {
suggestions = append(suggestions, "序列号必须是正整数")
}
return suggestions
}
// generateYearSuggestions 生成年份建议
func (v *CVEValidator) generateYearSuggestions(cveId string) []string {
if !v.enableSuggestions {
return nil
}
var suggestions []string
year := cve.ExtractCveYearAsInt(cveId)
currentYear := time.Now().Year()
if year < 1970 {
suggestions = append(suggestions, "CVE 系统始于 1970 年左右,请检查年份")
} else if year > currentYear+v.maxYearOffset {
suggestions = append(suggestions,
fmt.Sprintf("年份 %d 超出合理范围(当前年份+%d),请检查输入",
year, v.maxYearOffset))
}
return suggestions
}
2. 批量验证处理器
go
// BatchProcessor 批量处理器
type BatchProcessor struct {
validator *CVEValidator
maxBatchSize int
maxConcurrency int
}
func NewBatchProcessor(validator *CVEValidator) *BatchProcessor {
return &BatchProcessor{
validator: validator,
maxBatchSize: 10000,
maxConcurrency: 10,
}
}
// BatchValidationResult 批量验证结果
type BatchValidationResult struct {
TotalCount int `json:"total_count"`
ValidCount int `json:"valid_count"`
InvalidCount int `json:"invalid_count"`
ProcessTime time.Duration `json:"process_time_ns"`
ValidCVEs []string `json:"valid_cves"`
InvalidCVEs []ValidationResult `json:"invalid_cves"`
ErrorSummary map[string]int `json:"error_summary"`
}
// ValidateBatch 批量验证
func (bp *BatchProcessor) ValidateBatch(inputs []string) BatchValidationResult {
start := time.Now()
result := BatchValidationResult{
TotalCount: len(inputs),
ValidCVEs: make([]string, 0),
InvalidCVEs: make([]ValidationResult, 0),
ErrorSummary: make(map[string]int),
}
// 检查批量大小限制
if len(inputs) > bp.maxBatchSize {
// 分批处理
return bp.processBatchesSequentially(inputs)
}
// 并发处理
if len(inputs) > 100 && bp.maxConcurrency > 1 {
return bp.processBatchesConcurrently(inputs)
}
// 顺序处理
for _, input := range inputs {
validationResult := bp.validator.ValidateSingle(input)
if validationResult.IsValid {
result.ValidCount++
result.ValidCVEs = append(result.ValidCVEs, validationResult.CVE)
} else {
result.InvalidCount++
result.InvalidCVEs = append(result.InvalidCVEs, validationResult)
result.ErrorSummary[validationResult.ErrorType]++
}
}
result.ProcessTime = time.Since(start)
return result
}
// processBatchesConcurrently 并发处理批次
func (bp *BatchProcessor) processBatchesConcurrently(inputs []string) BatchValidationResult {
start := time.Now()
// 创建工作通道
inputChan := make(chan string, len(inputs))
resultChan := make(chan ValidationResult, len(inputs))
// 启动工作协程
for i := 0; i < bp.maxConcurrency; i++ {
go func() {
for input := range inputChan {
result := bp.validator.ValidateSingle(input)
resultChan <- result
}
}()
}
// 发送输入数据
for _, input := range inputs {
inputChan <- input
}
close(inputChan)
// 收集结果
result := BatchValidationResult{
TotalCount: len(inputs),
ValidCVEs: make([]string, 0),
InvalidCVEs: make([]ValidationResult, 0),
ErrorSummary: make(map[string]int),
}
for i := 0; i < len(inputs); i++ {
validationResult := <-resultChan
if validationResult.IsValid {
result.ValidCount++
result.ValidCVEs = append(result.ValidCVEs, validationResult.CVE)
} else {
result.InvalidCount++
result.InvalidCVEs = append(result.InvalidCVEs, validationResult)
result.ErrorSummary[validationResult.ErrorType]++
}
}
result.ProcessTime = time.Since(start)
return result
}
// processBatchesSequentially 分批顺序处理
func (bp *BatchProcessor) processBatchesSequentially(inputs []string) BatchValidationResult {
start := time.Now()
result := BatchValidationResult{
TotalCount: len(inputs),
ValidCVEs: make([]string, 0),
InvalidCVEs: make([]ValidationResult, 0),
ErrorSummary: make(map[string]int),
}
// 分批处理
for i := 0; i < len(inputs); i += bp.maxBatchSize {
end := i + bp.maxBatchSize
if end > len(inputs) {
end = len(inputs)
}
batch := inputs[i:end]
batchResult := bp.ValidateBatch(batch)
// 合并结果
result.ValidCount += batchResult.ValidCount
result.InvalidCount += batchResult.InvalidCount
result.ValidCVEs = append(result.ValidCVEs, batchResult.ValidCVEs...)
result.InvalidCVEs = append(result.InvalidCVEs, batchResult.InvalidCVEs...)
for errorType, count := range batchResult.ErrorSummary {
result.ErrorSummary[errorType] += count
}
fmt.Printf("已处理批次 %d-%d (%d/%d)\n", i+1, end, end, len(inputs))
}
result.ProcessTime = time.Since(start)
return result
}
3. 错误处理和恢复
go
// ErrorHandler 错误处理器
type ErrorHandler struct {
maxRetries int
retryDelay time.Duration
enableLogging bool
}
func NewErrorHandler() *ErrorHandler {
return &ErrorHandler{
maxRetries: 3,
retryDelay: 100 * time.Millisecond,
enableLogging: true,
}
}
// ProcessWithRetry 带重试的处理
func (eh *ErrorHandler) ProcessWithRetry(input string, validator *CVEValidator) ValidationResult {
var lastResult ValidationResult
for attempt := 0; attempt <= eh.maxRetries; attempt++ {
// 尝试处理
result := eh.safeValidate(input, validator)
// 如果成功或者是明确的格式错误,直接返回
if result.IsValid || result.ErrorType == "INVALID_FORMAT" || result.ErrorType == "EMPTY_INPUT" {
return result
}
lastResult = result
// 记录重试
if eh.enableLogging && attempt < eh.maxRetries {
fmt.Printf("验证失败,第 %d 次重试: %s (错误: %s)\n",
attempt+1, input, result.ErrorMsg)
}
// 等待后重试
if attempt < eh.maxRetries {
time.Sleep(eh.retryDelay)
}
}
// 所有重试都失败
lastResult.ErrorMsg = fmt.Sprintf("经过 %d 次重试后仍然失败: %s",
eh.maxRetries, lastResult.ErrorMsg)
return lastResult
}
// safeValidate 安全的验证函数
func (eh *ErrorHandler) safeValidate(input string, validator *CVEValidator) (result ValidationResult) {
defer func() {
if r := recover(); r != nil {
result = ValidationResult{
IsValid: false,
ErrorType: "PANIC_ERROR",
ErrorMsg: fmt.Sprintf("验证过程中发生异常: %v", r),
}
if eh.enableLogging {
fmt.Printf("验证异常: %v, 输入: %s\n", r, input)
}
}
}()
return validator.ValidateSingle(input)
}
// RecoverableProcessor 可恢复的处理器
type RecoverableProcessor struct {
validator *CVEValidator
errorHandler *ErrorHandler
failureLog []FailureRecord
}
type FailureRecord struct {
Input string `json:"input"`
Error string `json:"error"`
Timestamp time.Time `json:"timestamp"`
Attempts int `json:"attempts"`
}
func NewRecoverableProcessor() *RecoverableProcessor {
return &RecoverableProcessor{
validator: NewCVEValidator(),
errorHandler: NewErrorHandler(),
failureLog: make([]FailureRecord, 0),
}
}
// ProcessWithRecovery 带恢复的处理
func (rp *RecoverableProcessor) ProcessWithRecovery(inputs []string) BatchValidationResult {
result := BatchValidationResult{
TotalCount: len(inputs),
ValidCVEs: make([]string, 0),
InvalidCVEs: make([]ValidationResult, 0),
ErrorSummary: make(map[string]int),
}
start := time.Now()
for _, input := range inputs {
validationResult := rp.errorHandler.ProcessWithRetry(input, rp.validator)
if validationResult.IsValid {
result.ValidCount++
result.ValidCVEs = append(result.ValidCVEs, validationResult.CVE)
} else {
result.InvalidCount++
result.InvalidCVEs = append(result.InvalidCVEs, validationResult)
result.ErrorSummary[validationResult.ErrorType]++
// 记录失败
rp.failureLog = append(rp.failureLog, FailureRecord{
Input: input,
Error: validationResult.ErrorMsg,
Timestamp: time.Now(),
Attempts: rp.errorHandler.maxRetries + 1,
})
}
}
result.ProcessTime = time.Since(start)
return result
}
// GetFailureReport 获取失败报告
func (rp *RecoverableProcessor) GetFailureReport() map[string]interface{} {
errorTypes := make(map[string]int)
for _, failure := range rp.failureLog {
// 简单的错误分类
if strings.Contains(failure.Error, "格式") {
errorTypes["FORMAT_ERRORS"]++
} else if strings.Contains(failure.Error, "年份") {
errorTypes["YEAR_ERRORS"]++
} else if strings.Contains(failure.Error, "异常") {
errorTypes["SYSTEM_ERRORS"]++
} else {
errorTypes["OTHER_ERRORS"]++
}
}
return map[string]interface{}{
"total_failures": len(rp.failureLog),
"error_distribution": errorTypes,
"recent_failures": rp.getRecentFailures(10),
"failure_rate": rp.calculateFailureRate(),
}
}
func (rp *RecoverableProcessor) getRecentFailures(limit int) []FailureRecord {
if len(rp.failureLog) <= limit {
return rp.failureLog
}
return rp.failureLog[len(rp.failureLog)-limit:]
}
func (rp *RecoverableProcessor) calculateFailureRate() float64 {
if len(rp.failureLog) == 0 {
return 0.0
}
// 计算最近一小时的失败率
oneHourAgo := time.Now().Add(-time.Hour)
recentFailures := 0
for _, failure := range rp.failureLog {
if failure.Timestamp.After(oneHourAgo) {
recentFailures++
}
}
return float64(recentFailures) / float64(len(rp.failureLog)) * 100
}
4. 性能优化
go
// PerformanceOptimizer 性能优化器
type PerformanceOptimizer struct {
cache map[string]ValidationResult
cacheSize int
cacheHits int
cacheMisses int
enableCache bool
enableMetrics bool
}
func NewPerformanceOptimizer() *PerformanceOptimizer {
return &PerformanceOptimizer{
cache: make(map[string]ValidationResult),
cacheSize: 10000,
enableCache: true,
enableMetrics: true,
}
}
// OptimizedValidate 优化的验证函数
func (po *PerformanceOptimizer) OptimizedValidate(input string, validator *CVEValidator) ValidationResult {
// 缓存查找
if po.enableCache {
if cached, exists := po.cache[input]; exists {
po.cacheHits++
return cached
}
po.cacheMisses++
}
// 执行验证
result := validator.ValidateSingle(input)
// 缓存结果
if po.enableCache && len(po.cache) < po.cacheSize {
po.cache[input] = result
}
return result
}
// GetCacheStats 获取缓存统计
func (po *PerformanceOptimizer) GetCacheStats() map[string]interface{} {
total := po.cacheHits + po.cacheMisses
hitRate := 0.0
if total > 0 {
hitRate = float64(po.cacheHits) / float64(total) * 100
}
return map[string]interface{}{
"cache_size": len(po.cache),
"cache_hits": po.cacheHits,
"cache_misses": po.cacheMisses,
"hit_rate": hitRate,
"max_cache_size": po.cacheSize,
}
}
// ClearCache 清空缓存
func (po *PerformanceOptimizer) ClearCache() {
po.cache = make(map[string]ValidationResult)
po.cacheHits = 0
po.cacheMisses = 0
}
// BenchmarkValidator 性能基准测试
func BenchmarkValidator(validator *CVEValidator, testData []string, iterations int) {
fmt.Printf("开始性能基准测试: %d 次迭代, %d 个测试样本\n", iterations, len(testData))
start := time.Now()
totalProcessed := 0
for i := 0; i < iterations; i++ {
for _, input := range testData {
validator.ValidateSingle(input)
totalProcessed++
}
}
duration := time.Since(start)
avgTime := duration / time.Duration(totalProcessed)
throughput := float64(totalProcessed) / duration.Seconds()
fmt.Printf("基准测试结果:\n")
fmt.Printf(" 总处理数: %d\n", totalProcessed)
fmt.Printf(" 总耗时: %v\n", duration)
fmt.Printf(" 平均耗时: %v\n", avgTime)
fmt.Printf(" 吞吐量: %.2f 次/秒\n", throughput)
}
5. 主程序示例
go
func main() {
fmt.Println("=== CVE 验证处理系统 ===")
// 1. 基本验证示例
fmt.Println("\n1. 基本验证示例")
validator := NewCVEValidator()
testInputs := []string{
"CVE-2022-12345", // 有效
" cve-2021-44228 ", // 有效(需要格式化)
"2022-12345", // 无效(缺少前缀)
"CVE-2022-ABC", // 无效(序列号不是数字)
"", // 无效(空输入)
"CVE/2022/12345", // 无效(错误分隔符)
}
for _, input := range testInputs {
result := validator.ValidateSingle(input)
fmt.Printf("输入: %-20s -> ", fmt.Sprintf("'%s'", input))
if result.IsValid {
fmt.Printf("✅ 有效: %s\n", result.CVE)
} else {
fmt.Printf("❌ 无效: %s\n", result.ErrorMsg)
if len(result.Suggestions) > 0 {
fmt.Printf(" 建议: %s\n", result.Suggestions[0])
}
}
}
// 2. 批量验证示例
fmt.Println("\n2. 批量验证示例")
batchProcessor := NewBatchProcessor(validator)
largeBatch := []string{
"CVE-2021-44228", "CVE-2022-12345", "CVE-2023-1234",
"invalid-cve", "CVE-2024-5678", "2022-9999",
"CVE-2020-1111", "cve-2021-2222", "",
}
batchResult := batchProcessor.ValidateBatch(largeBatch)
fmt.Printf("批量验证结果:\n")
fmt.Printf(" 总数: %d\n", batchResult.TotalCount)
fmt.Printf(" 有效: %d (%.1f%%)\n", batchResult.ValidCount,
float64(batchResult.ValidCount)/float64(batchResult.TotalCount)*100)
fmt.Printf(" 无效: %d (%.1f%%)\n", batchResult.InvalidCount,
float64(batchResult.InvalidCount)/float64(batchResult.TotalCount)*100)
fmt.Printf(" 处理时间: %v\n", batchResult.ProcessTime)
fmt.Printf(" 错误分布:\n")
for errorType, count := range batchResult.ErrorSummary {
fmt.Printf(" %s: %d\n", errorType, count)
}
// 3. 错误处理和恢复示例
fmt.Println("\n3. 错误处理和恢复示例")
recoverable := NewRecoverableProcessor()
problematicInputs := []string{
"CVE-2022-12345",
"invalid-format",
"CVE-1960-12345", // 年份过早
"CVE-2099-12345", // 年份过晚
}
recoveryResult := recoverable.ProcessWithRecovery(problematicInputs)
fmt.Printf("恢复处理结果: %d 有效, %d 无效\n",
recoveryResult.ValidCount, recoveryResult.InvalidCount)
failureReport := recoverable.GetFailureReport()
fmt.Printf("失败报告: %v\n", failureReport)
// 4. 性能优化示例
fmt.Println("\n4. 性能优化示例")
optimizer := NewPerformanceOptimizer()
// 测试缓存效果
testData := []string{"CVE-2022-12345", "CVE-2021-44228", "CVE-2023-1234"}
// 第一次验证(缓存未命中)
for _, input := range testData {
optimizer.OptimizedValidate(input, validator)
}
// 第二次验证(缓存命中)
for _, input := range testData {
optimizer.OptimizedValidate(input, validator)
}
cacheStats := optimizer.GetCacheStats()
fmt.Printf("缓存统计: %v\n", cacheStats)
// 5. 性能基准测试
fmt.Println("\n5. 性能基准测试")
benchmarkData := []string{
"CVE-2022-12345", "CVE-2021-44228", "CVE-2023-1234",
"CVE-2020-1111", "CVE-2024-5678",
}
BenchmarkValidator(validator, benchmarkData, 1000)
fmt.Println("\n=== 验证处理系统演示完成 ===")
}
Web API 集成示例
go
// HTTP 处理器示例
func handleCVEValidation(w http.ResponseWriter, r *http.Request) {
validator := NewCVEValidator()
validator.SetStrictMode(true)
cveInput := r.URL.Query().Get("cve")
if cveInput == "" {
http.Error(w, "缺少 CVE 参数", http.StatusBadRequest)
return
}
result := validator.ValidateSingle(cveInput)
w.Header().Set("Content-Type", "application/json")
if result.IsValid {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusBadRequest)
}
json.NewEncoder(w).Encode(result)
}
// 批量验证 API
func handleBatchValidation(w http.ResponseWriter, r *http.Request) {
var request struct {
CVEs []string `json:"cves"`
}
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
http.Error(w, "无效的 JSON 格式", http.StatusBadRequest)
return
}
validator := NewCVEValidator()
processor := NewBatchProcessor(validator)
result := processor.ValidateBatch(request.CVEs)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(result)
}
最佳实践
- 分层验证: 先进行基本格式检查,再进行详细验证
- 缓存优化: 对重复验证的 CVE 使用缓存
- 错误恢复: 实现重试机制和优雅降级
- 性能监控: 监控验证性能和错误率
- 用户友好: 提供清晰的错误信息和修复建议
这个示例展示了如何构建一个健壮、高性能的 CVE 验证系统,适用于各种生产环境。