漏洞报告分析
本示例展示如何使用 CVE Utils 分析安全公告、漏洞报告和相关文档,提取有价值的漏洞信息并生成分析报告。
场景描述
作为安全团队成员,您需要:
- 从各种安全公告中提取 CVE 信息
- 分析漏洞的时间分布和趋势
- 生成统计报告供管理层参考
- 识别需要优先处理的漏洞
完整示例
1. 安全公告分析器
go
package main
import (
"fmt"
"sort"
"strings"
"time"
"github.com/scagogogo/cve"
)
// SecurityBulletin 表示一个安全公告
type SecurityBulletin struct {
ID string
Title string
Content string
PublishDate time.Time
Source string
}
// VulnerabilityAnalyzer 漏洞分析器
type VulnerabilityAnalyzer struct {
bulletins []SecurityBulletin
}
func NewVulnerabilityAnalyzer() *VulnerabilityAnalyzer {
return &VulnerabilityAnalyzer{
bulletins: make([]SecurityBulletin, 0),
}
}
func (va *VulnerabilityAnalyzer) AddBulletin(bulletin SecurityBulletin) {
va.bulletins = append(va.bulletins, bulletin)
}
// AnalyzeAllBulletins 分析所有公告
func (va *VulnerabilityAnalyzer) AnalyzeAllBulletins() *AnalysisReport {
fmt.Println("=== 开始分析安全公告 ===")
var allCves []string
bulletinCves := make(map[string][]string)
// 从每个公告中提取 CVE
for _, bulletin := range va.bulletins {
cves := va.extractCvesFromBulletin(bulletin)
allCves = append(allCves, cves...)
bulletinCves[bulletin.ID] = cves
fmt.Printf("公告 %s: 发现 %d 个 CVE\n", bulletin.ID, len(cves))
}
// 数据清洗
cleanedCves := va.cleanCveData(allCves)
// 生成分析报告
report := va.generateAnalysisReport(cleanedCves, bulletinCves)
return report
}
// extractCvesFromBulletin 从公告中提取 CVE
func (va *VulnerabilityAnalyzer) extractCvesFromBulletin(bulletin SecurityBulletin) []string {
// 合并标题和内容进行分析
fullText := bulletin.Title + "\n" + bulletin.Content
// 检查是否包含 CVE
if !cve.IsContainsCve(fullText) {
return []string{}
}
// 提取所有 CVE
cves := cve.ExtractCve(fullText)
// 验证每个 CVE
var validCves []string
for _, cveId := range cves {
if cve.ValidateCve(cveId) {
validCves = append(validCves, cveId)
} else {
fmt.Printf("警告: 发现无效 CVE %s 在公告 %s 中\n", cveId, bulletin.ID)
}
}
return validCves
}
// cleanCveData 清洗 CVE 数据
func (va *VulnerabilityAnalyzer) cleanCveData(rawCves []string) []string {
fmt.Printf("数据清洗: 原始数据 %d 个 CVE\n", len(rawCves))
// 去重
unique := cve.RemoveDuplicateCves(rawCves)
fmt.Printf("去重后: %d 个 CVE\n", len(unique))
// 排序
sorted := cve.SortCves(unique)
fmt.Printf("排序完成\n")
return sorted
}
2. 分析报告生成
go
// AnalysisReport 分析报告结构
type AnalysisReport struct {
TotalCves int
UniqueCves int
YearDistribution map[string]int
RecentTrends map[int]int
TopYears []string
CriticalFindings []string
Summary string
}
// generateAnalysisReport 生成分析报告
func (va *VulnerabilityAnalyzer) generateAnalysisReport(cves []string, bulletinCves map[string][]string) *AnalysisReport {
report := &AnalysisReport{
UniqueCves: len(cves),
YearDistribution: make(map[string]int),
RecentTrends: make(map[int]int),
CriticalFindings: make([]string, 0),
}
// 计算总 CVE 数(包括重复)
totalCount := 0
for _, bulletinCveList := range bulletinCves {
totalCount += len(bulletinCveList)
}
report.TotalCves = totalCount
// 年份分布分析
grouped := cve.GroupByYear(cves)
for year, yearCves := range grouped {
report.YearDistribution[year] = len(yearCves)
}
// 最近几年趋势
for i := 1; i <= 5; i++ {
recent := cve.GetRecentCves(cves, i)
report.RecentTrends[i] = len(recent)
}
// 找出 CVE 最多的年份
report.TopYears = va.findTopYears(report.YearDistribution)
// 关键发现
report.CriticalFindings = va.identifyCriticalFindings(cves, grouped)
// 生成摘要
report.Summary = va.generateSummary(report)
return report
}
// findTopYears 找出 CVE 最多的年份
func (va *VulnerabilityAnalyzer) findTopYears(yearDist map[string]int) []string {
maxCount := 0
var topYears []string
for year, count := range yearDist {
if count > maxCount {
maxCount = count
topYears = []string{year}
} else if count == maxCount {
topYears = append(topYears, year)
}
}
sort.Strings(topYears)
return topYears
}
// identifyCriticalFindings 识别关键发现
func (va *VulnerabilityAnalyzer) identifyCriticalFindings(cves []string, grouped map[string][]string) []string {
var findings []string
// 检查是否有大量最近的漏洞
currentYear := time.Now().Year()
thisYearCves := cve.FilterCvesByYear(cves, currentYear)
if len(thisYearCves) > 10 {
findings = append(findings, fmt.Sprintf("今年发现了 %d 个漏洞,需要重点关注", len(thisYearCves)))
}
// 检查是否有异常年份
avgPerYear := float64(len(cves)) / float64(len(grouped))
for year, yearCves := range grouped {
if float64(len(yearCves)) > avgPerYear*1.5 {
findings = append(findings, fmt.Sprintf("%s年漏洞数量异常高: %d个", year, len(yearCves)))
}
}
// 检查最近趋势
recent1 := cve.GetRecentCves(cves, 1)
recent2 := cve.GetRecentCves(cves, 2)
if len(recent1) > len(recent2)/2 {
findings = append(findings, "最近一年漏洞增长迅速,建议加强安全防护")
}
return findings
}
// generateSummary 生成摘要
func (va *VulnerabilityAnalyzer) generateSummary(report *AnalysisReport) string {
var summary strings.Builder
summary.WriteString(fmt.Sprintf("本次分析共处理 %d 个 CVE(去重后 %d 个)。",
report.TotalCves, report.UniqueCves))
if len(report.YearDistribution) > 0 {
summary.WriteString(fmt.Sprintf("漏洞分布在 %d 个年份中,", len(report.YearDistribution)))
if len(report.TopYears) > 0 {
summary.WriteString(fmt.Sprintf("其中 %s 年漏洞数量最多。",
strings.Join(report.TopYears, "、")))
}
}
if len(report.CriticalFindings) > 0 {
summary.WriteString("发现以下关键问题需要关注。")
}
return summary.String()
}
3. 报告输出和可视化
go
// PrintReport 打印分析报告
func (va *VulnerabilityAnalyzer) PrintReport(report *AnalysisReport) {
fmt.Println("\n" + strings.Repeat("=", 50))
fmt.Println(" 漏洞分析报告")
fmt.Println(strings.Repeat("=", 50))
// 基本统计
fmt.Printf("总 CVE 数量: %d\n", report.TotalCves)
fmt.Printf("唯一 CVE 数量: %d\n", report.UniqueCves)
fmt.Printf("重复率: %.1f%%\n",
float64(report.TotalCves-report.UniqueCves)/float64(report.TotalCves)*100)
// 年份分布
fmt.Println("\n年份分布:")
years := make([]string, 0, len(report.YearDistribution))
for year := range report.YearDistribution {
years = append(years, year)
}
sort.Strings(years)
for _, year := range years {
count := report.YearDistribution[year]
percentage := float64(count) / float64(report.UniqueCves) * 100
bar := strings.Repeat("█", count/2) // 简单的条形图
fmt.Printf(" %s年: %3d个 (%5.1f%%) %s\n", year, count, percentage, bar)
}
// 最近趋势
fmt.Println("\n最近趋势:")
for i := 1; i <= 5; i++ {
count := report.RecentTrends[i]
fmt.Printf(" 最近%d年: %d个\n", i, count)
}
// 关键发现
if len(report.CriticalFindings) > 0 {
fmt.Println("\n关键发现:")
for i, finding := range report.CriticalFindings {
fmt.Printf(" %d. %s\n", i+1, finding)
}
}
// 摘要
fmt.Println("\n摘要:")
fmt.Printf(" %s\n", report.Summary)
fmt.Println(strings.Repeat("=", 50))
}
// ExportToCSV 导出为 CSV 格式
func (va *VulnerabilityAnalyzer) ExportToCSV(cves []string, filename string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
// 写入标题行
headers := []string{"CVE", "Year", "Sequence", "Age_Years"}
writer.Write(headers)
currentYear := time.Now().Year()
// 写入数据行
for _, cveId := range cves {
year := cve.ExtractCveYearAsInt(cveId)
seq := cve.ExtractCveSeqAsInt(cveId)
age := currentYear - year
record := []string{
cveId,
fmt.Sprintf("%d", year),
fmt.Sprintf("%d", seq),
fmt.Sprintf("%d", age),
}
writer.Write(record)
}
return nil
}
4. 主程序示例
go
func main() {
// 创建分析器
analyzer := NewVulnerabilityAnalyzer()
// 添加示例安全公告
bulletins := []SecurityBulletin{
{
ID: "SEC-2024-001",
Title: "关键安全更新 - 修复多个高危漏洞",
Content: `
本次更新修复了以下关键漏洞:
1. CVE-2021-44228 - Apache Log4j 远程代码执行漏洞
2. CVE-2022-12345 - 自定义组件权限提升漏洞
3. CVE-2023-1234 - 第三方库信息泄露漏洞
建议所有用户立即更新到最新版本。
`,
PublishDate: time.Now().AddDate(0, -1, 0),
Source: "内部安全团队",
},
{
ID: "SEC-2024-002",
Title: "紧急安全补丁",
Content: `
发现新的零日漏洞:
- CVE-2024-5678 - 核心组件远程代码执行
- cve-2024-9999 - 认证绕过漏洞
同时修复了之前报告的 CVE-2023-1234。
`,
PublishDate: time.Now().AddDate(0, 0, -7),
Source: "外部安全研究员",
},
{
ID: "SEC-2024-003",
Title: "月度安全更新",
Content: `
本月修复的漏洞包括:
CVE-2022-11111, CVE-2022-22222, CVE-2023-33333
以及多个低危漏洞 CVE-2024-1111 到 CVE-2024-1115。
`,
PublishDate: time.Now().AddDate(0, 0, -15),
Source: "产品安全团队",
},
}
// 添加公告到分析器
for _, bulletin := range bulletins {
analyzer.AddBulletin(bulletin)
}
// 执行分析
report := analyzer.AnalyzeAllBulletins()
// 打印报告
analyzer.PrintReport(report)
// 导出数据
allCves := []string{}
for _, bulletin := range bulletins {
cves := analyzer.extractCvesFromBulletin(bulletin)
allCves = append(allCves, cves...)
}
cleanedCves := analyzer.cleanCveData(allCves)
if err := analyzer.ExportToCSV(cleanedCves, "vulnerability_analysis.csv"); err != nil {
fmt.Printf("导出 CSV 失败: %v\n", err)
} else {
fmt.Println("数据已导出到 vulnerability_analysis.csv")
}
}
高级分析功能
1. 时间序列分析
go
func (va *VulnerabilityAnalyzer) analyzeTimeSeries(cves []string) {
fmt.Println("\n=== 时间序列分析 ===")
grouped := cve.GroupByYear(cves)
// 按年份排序
years := make([]string, 0, len(grouped))
for year := range grouped {
years = append(years, year)
}
sort.Strings(years)
// 计算年度增长率
fmt.Println("年度增长率:")
for i := 1; i < len(years); i++ {
prevYear := years[i-1]
currYear := years[i]
prevCount := len(grouped[prevYear])
currCount := len(grouped[currYear])
if prevCount > 0 {
growthRate := float64(currCount-prevCount) / float64(prevCount) * 100
fmt.Printf(" %s -> %s: %+.1f%% (%d -> %d)\n",
prevYear, currYear, growthRate, prevCount, currCount)
}
}
// 移动平均
if len(years) >= 3 {
fmt.Println("\n3年移动平均:")
for i := 2; i < len(years); i++ {
sum := 0
for j := i - 2; j <= i; j++ {
sum += len(grouped[years[j]])
}
avg := float64(sum) / 3.0
fmt.Printf(" %s: %.1f\n", years[i], avg)
}
}
}
2. 严重性评估
go
func (va *VulnerabilityAnalyzer) assessSeverity(cves []string) map[string]string {
severity := make(map[string]string)
for _, cveId := range cves {
year := cve.ExtractCveYearAsInt(cveId)
seq := cve.ExtractCveSeqAsInt(cveId)
// 简单的严重性评估逻辑(实际应用中应该查询 CVSS 数据库)
currentYear := time.Now().Year()
age := currentYear - year
if age <= 1 && seq > 10000 {
severity[cveId] = "Critical"
} else if age <= 2 && seq > 5000 {
severity[cveId] = "High"
} else if age <= 3 {
severity[cveId] = "Medium"
} else {
severity[cveId] = "Low"
}
}
return severity
}
3. 相关性分析
go
func (va *VulnerabilityAnalyzer) analyzeCorrelations(bulletinCves map[string][]string) {
fmt.Println("\n=== 相关性分析 ===")
// 找出经常一起出现的 CVE
cooccurrence := make(map[string]map[string]int)
for _, cves := range bulletinCves {
for i, cveA := range cves {
if cooccurrence[cveA] == nil {
cooccurrence[cveA] = make(map[string]int)
}
for j, cveB := range cves {
if i != j {
cooccurrence[cveA][cveB]++
}
}
}
}
// 输出高相关性的 CVE 对
fmt.Println("高相关性 CVE 对:")
for cveA, related := range cooccurrence {
for cveB, count := range related {
if count >= 2 && cveA < cveB { // 避免重复输出
fmt.Printf(" %s <-> %s: 共同出现 %d 次\n", cveA, cveB, count)
}
}
}
}
使用场景
1. 安全团队日常分析
bash
# 运行分析器
go run vulnerability_analyzer.go
# 查看生成的报告
cat vulnerability_analysis.csv
2. 自动化集成
go
// 定期分析任务
func scheduleAnalysis() {
ticker := time.NewTicker(24 * time.Hour) // 每天运行一次
defer ticker.Stop()
for {
select {
case <-ticker.C:
analyzer := NewVulnerabilityAnalyzer()
// 从数据源加载最新公告
// analyzer.LoadFromDatabase()
report := analyzer.AnalyzeAllBulletins()
// 发送报告
// sendReportToTeam(report)
}
}
}
3. 与其他系统集成
go
// 与威胁情报系统集成
func enrichWithThreatIntel(cves []string) map[string]ThreatInfo {
threatInfo := make(map[string]ThreatInfo)
for _, cveId := range cves {
// 查询威胁情报数据库
info := queryThreatIntelligence(cveId)
threatInfo[cveId] = info
}
return threatInfo
}
最佳实践
- 数据验证: 始终验证提取的 CVE 格式
- 错误处理: 对无效数据进行适当的错误处理
- 性能优化: 对大量数据使用批量处理
- 报告格式: 提供多种输出格式(控制台、CSV、JSON)
- 自动化: 集成到 CI/CD 流程中进行定期分析
这个示例展示了如何使用 CVE Utils 构建一个完整的漏洞分析系统,可以根据实际需求进行扩展和定制。