搜索和过滤
本示例展示如何使用CWE Go库的搜索和过滤功能来查找特定的CWE数据。
基本搜索
关键字搜索
go
package main
import (
"fmt"
"log"
"github.com/scagogogo/cwe"
)
func main() {
// 创建注册表
registry := cwe.NewCWERegistry()
// 添加一些测试数据
testData := []*cwe.CWEWeakness{
{
ID: "79",
Name: "跨站脚本",
Description: "应用程序在生成网页时未正确验证输入,导致恶意脚本执行",
Severity: "Medium",
},
{
ID: "89",
Name: "SQL注入",
Description: "应用程序在构造SQL命令时未正确验证输入",
Severity: "High",
},
{
ID: "78",
Name: "OS命令注入",
Description: "应用程序在构造操作系统命令时未正确验证输入",
Severity: "High",
},
{
ID: "352",
Name: "跨站请求伪造",
Description: "应用程序未验证请求是否来自可信源",
Severity: "Medium",
},
}
// 添加到注册表
for _, weakness := range testData {
registry.AddCWE(weakness)
}
// 搜索包含"注入"的CWE
fmt.Println("搜索关键字 '注入':")
results := registry.SearchByKeyword("注入")
fmt.Printf("找到 %d 个结果:\n", len(results))
for _, result := range results {
fmt.Printf("- CWE-%s: %s\n", result.GetID(), result.GetName())
}
// 搜索包含"脚本"的CWE
fmt.Println("\n搜索关键字 '脚本':")
scriptResults := registry.SearchByKeyword("脚本")
fmt.Printf("找到 %d 个结果:\n", len(scriptResults))
for _, result := range scriptResults {
fmt.Printf("- CWE-%s: %s\n", result.GetID(), result.GetName())
}
}
多关键字搜索
go
package main
import (
"fmt"
"strings"
"github.com/scagogogo/cwe"
)
func searchMultipleKeywords(registry *cwe.CWERegistry, keywords []string) []interface{} {
var results []interface{}
allData := registry.GetAll()
for _, item := range allData {
text := getSearchableText(item)
matchesAll := true
// 检查是否包含所有关键字
for _, keyword := range keywords {
if !strings.Contains(strings.ToLower(text), strings.ToLower(keyword)) {
matchesAll = false
break
}
}
if matchesAll {
results = append(results, item)
}
}
return results
}
func getSearchableText(item interface{}) string {
switch data := item.(type) {
case *cwe.CWEWeakness:
return data.Name + " " + data.Description
case *cwe.CWECategory:
return data.Name + " " + data.Description
case *cwe.CWEView:
return data.Name + " " + data.Description
default:
return ""
}
}
func main() {
registry := createSampleRegistry()
// 搜索同时包含"应用程序"和"验证"的CWE
keywords := []string{"应用程序", "验证"}
results := searchMultipleKeywords(registry, keywords)
fmt.Printf("搜索关键字 %v:\n", keywords)
fmt.Printf("找到 %d 个结果:\n", len(results))
for _, result := range results {
switch data := result.(type) {
case *cwe.CWEWeakness:
fmt.Printf("- CWE-%s: %s\n", data.ID, data.Name)
}
}
}
func createSampleRegistry() *cwe.CWERegistry {
registry := cwe.NewCWERegistry()
testData := []*cwe.CWEWeakness{
{
ID: "79",
Name: "跨站脚本",
Description: "应用程序在生成网页时未正确验证输入",
Severity: "Medium",
},
{
ID: "89",
Name: "SQL注入",
Description: "应用程序在构造SQL命令时未正确验证输入",
Severity: "High",
},
{
ID: "20",
Name: "输入验证不当",
Description: "产品未正确验证输入",
Severity: "Low",
},
}
for _, weakness := range testData {
registry.AddCWE(weakness)
}
return registry
}
高级过滤
按严重程度过滤
go
package main
import (
"fmt"
"github.com/scagogogo/cwe"
)
func filterBySeverity(registry *cwe.CWERegistry, severity string) []*cwe.CWEWeakness {
var results []*cwe.CWEWeakness
weaknesses := registry.GetWeaknesses()
for _, weakness := range weaknesses {
if weakness.Severity == severity {
results = append(results, weakness)
}
}
return results
}
func main() {
registry := createSampleRegistry()
// 按不同严重程度过滤
severities := []string{"High", "Medium", "Low"}
for _, severity := range severities {
results := filterBySeverity(registry, severity)
fmt.Printf("%s严重程度的弱点 (%d个):\n", severity, len(results))
for _, weakness := range results {
fmt.Printf(" - CWE-%s: %s\n", weakness.ID, weakness.Name)
}
fmt.Println()
}
}
按ID范围过滤
go
package main
import (
"fmt"
"strconv"
"github.com/scagogogo/cwe"
)
func filterByIDRange(registry *cwe.CWERegistry, minID, maxID int) []interface{} {
var results []interface{}
allData := registry.GetAll()
for _, item := range allData {
id := getNumericID(item)
if id >= minID && id <= maxID {
results = append(results, item)
}
}
return results
}
func getNumericID(item interface{}) int {
var idStr string
switch data := item.(type) {
case *cwe.CWEWeakness:
idStr = data.ID
case *cwe.CWECategory:
idStr = data.ID
case *cwe.CWEView:
idStr = data.ID
default:
return 0
}
id, err := strconv.Atoi(idStr)
if err != nil {
return 0
}
return id
}
func main() {
registry := createExtendedRegistry()
// 过滤ID在70-90范围内的CWE
results := filterByIDRange(registry, 70, 90)
fmt.Printf("ID在70-90范围内的CWE (%d个):\n", len(results))
for _, result := range results {
switch data := result.(type) {
case *cwe.CWEWeakness:
fmt.Printf(" - CWE-%s: %s [%s]\n", data.ID, data.Name, data.Severity)
case *cwe.CWECategory:
fmt.Printf(" - CWE-%s: %s [类别]\n", data.ID, data.Name)
}
}
}
func createExtendedRegistry() *cwe.CWERegistry {
registry := cwe.NewCWERegistry()
testData := []*cwe.CWEWeakness{
{ID: "79", Name: "跨站脚本", Severity: "Medium"},
{ID: "89", Name: "SQL注入", Severity: "High"},
{ID: "78", Name: "OS命令注入", Severity: "High"},
{ID: "77", Name: "路径遍历", Severity: "Medium"},
{ID: "95", Name: "代码注入", Severity: "High"},
{ID: "352", Name: "跨站请求伪造", Severity: "Medium"},
}
for _, weakness := range testData {
registry.AddCWE(weakness)
}
return registry
}
复合过滤条件
自定义过滤器
go
package main
import (
"fmt"
"strings"
"github.com/scagogogo/cwe"
)
type FilterCriteria struct {
Keywords []string
Severity string
IDRange *IDRange
NameMinLength int
NameMaxLength int
ExcludeKeywords []string
}
type IDRange struct {
Min, Max int
}
func advancedFilter(registry *cwe.CWERegistry, criteria FilterCriteria) []*cwe.CWEWeakness {
var results []*cwe.CWEWeakness
weaknesses := registry.GetWeaknesses()
for _, weakness := range weaknesses {
if matchesCriteria(weakness, criteria) {
results = append(results, weakness)
}
}
return results
}
func matchesCriteria(weakness *cwe.CWEWeakness, criteria FilterCriteria) bool {
// 检查关键字
if len(criteria.Keywords) > 0 {
text := strings.ToLower(weakness.Name + " " + weakness.Description)
for _, keyword := range criteria.Keywords {
if !strings.Contains(text, strings.ToLower(keyword)) {
return false
}
}
}
// 检查排除关键字
if len(criteria.ExcludeKeywords) > 0 {
text := strings.ToLower(weakness.Name + " " + weakness.Description)
for _, keyword := range criteria.ExcludeKeywords {
if strings.Contains(text, strings.ToLower(keyword)) {
return false
}
}
}
// 检查严重程度
if criteria.Severity != "" && weakness.Severity != criteria.Severity {
return false
}
// 检查ID范围
if criteria.IDRange != nil {
id := getNumericID(weakness)
if id < criteria.IDRange.Min || id > criteria.IDRange.Max {
return false
}
}
// 检查名称长度
nameLength := len(weakness.Name)
if criteria.NameMinLength > 0 && nameLength < criteria.NameMinLength {
return false
}
if criteria.NameMaxLength > 0 && nameLength > criteria.NameMaxLength {
return false
}
return true
}
func main() {
registry := createExtendedRegistry()
// 复合过滤条件示例
criteria := FilterCriteria{
Keywords: []string{"注入"},
Severity: "High",
IDRange: &IDRange{Min: 70, Max: 100},
NameMinLength: 3,
NameMaxLength: 20,
}
results := advancedFilter(registry, criteria)
fmt.Printf("复合过滤结果 (%d个):\n", len(results))
fmt.Printf("条件: 包含'注入', 高严重程度, ID在70-100, 名称长度3-20字符\n\n")
for _, weakness := range results {
fmt.Printf("- CWE-%s: %s [%s]\n", weakness.ID, weakness.Name, weakness.Severity)
fmt.Printf(" 名称长度: %d字符\n", len(weakness.Name))
fmt.Println()
}
}
搜索结果排序
按相关性排序
go
package main
import (
"fmt"
"sort"
"strings"
"github.com/scagogogo/cwe"
)
type SearchResult struct {
Weakness *cwe.CWEWeakness
Relevance int
}
func searchWithRelevance(registry *cwe.CWERegistry, keyword string) []SearchResult {
var results []SearchResult
weaknesses := registry.GetWeaknesses()
for _, weakness := range weaknesses {
relevance := calculateRelevance(weakness, keyword)
if relevance > 0 {
results = append(results, SearchResult{
Weakness: weakness,
Relevance: relevance,
})
}
}
// 按相关性排序(降序)
sort.Slice(results, func(i, j int) bool {
return results[i].Relevance > results[j].Relevance
})
return results
}
func calculateRelevance(weakness *cwe.CWEWeakness, keyword string) int {
keyword = strings.ToLower(keyword)
name := strings.ToLower(weakness.Name)
description := strings.ToLower(weakness.Description)
relevance := 0
// 名称中的匹配权重更高
if strings.Contains(name, keyword) {
relevance += 10
// 完全匹配权重最高
if name == keyword {
relevance += 20
}
// 开头匹配权重较高
if strings.HasPrefix(name, keyword) {
relevance += 15
}
}
// 描述中的匹配
if strings.Contains(description, keyword) {
relevance += 5
// 计算出现次数
count := strings.Count(description, keyword)
relevance += count * 2
}
return relevance
}
func main() {
registry := createExtendedRegistry()
keyword := "注入"
results := searchWithRelevance(registry, keyword)
fmt.Printf("搜索 '%s' 的结果(按相关性排序):\n\n", keyword)
for i, result := range results {
fmt.Printf("%d. CWE-%s: %s [相关性: %d]\n",
i+1, result.Weakness.ID, result.Weakness.Name, result.Relevance)
fmt.Printf(" 严重程度: %s\n", result.Weakness.Severity)
fmt.Printf(" 描述: %s\n", result.Weakness.Description)
fmt.Println()
}
}
搜索统计
搜索结果分析
go
package main
import (
"fmt"
"github.com/scagogogo/cwe"
)
type SearchStats struct {
TotalResults int
SeverityCount map[string]int
AverageNameLength float64
IDRanges map[string]int
}
func analyzeSearchResults(results []*cwe.CWEWeakness) SearchStats {
stats := SearchStats{
TotalResults: len(results),
SeverityCount: make(map[string]int),
IDRanges: make(map[string]int),
}
if len(results) == 0 {
return stats
}
totalNameLength := 0
for _, weakness := range results {
// 统计严重程度
if weakness.Severity != "" {
stats.SeverityCount[weakness.Severity]++
} else {
stats.SeverityCount["Unknown"]++
}
// 计算名称长度
totalNameLength += len(weakness.Name)
// 统计ID范围
id := getNumericID(weakness)
switch {
case id < 100:
stats.IDRanges["1-99"]++
case id < 200:
stats.IDRanges["100-199"]++
case id < 300:
stats.IDRanges["200-299"]++
case id < 400:
stats.IDRanges["300-399"]++
default:
stats.IDRanges["400+"]++
}
}
stats.AverageNameLength = float64(totalNameLength) / float64(len(results))
return stats
}
func printSearchStats(keyword string, stats SearchStats) {
fmt.Printf("搜索 '%s' 的统计信息:\n", keyword)
fmt.Printf("总结果数: %d\n\n", stats.TotalResults)
if stats.TotalResults == 0 {
return
}
fmt.Println("严重程度分布:")
for severity, count := range stats.SeverityCount {
percentage := float64(count) / float64(stats.TotalResults) * 100
fmt.Printf(" %s: %d个 (%.1f%%)\n", severity, count, percentage)
}
fmt.Printf("\n平均名称长度: %.1f字符\n", stats.AverageNameLength)
fmt.Println("\nID范围分布:")
for idRange, count := range stats.IDRanges {
percentage := float64(count) / float64(stats.TotalResults) * 100
fmt.Printf(" %s: %d个 (%.1f%%)\n", idRange, count, percentage)
}
}
func main() {
registry := createLargeRegistry()
// 搜索并分析结果
keywords := []string{"注入", "脚本", "验证"}
for _, keyword := range keywords {
results := registry.SearchByKeyword(keyword)
// 转换为弱点列表
var weaknesses []*cwe.CWEWeakness
for _, result := range results {
if weakness, ok := result.(*cwe.CWEWeakness); ok {
weaknesses = append(weaknesses, weakness)
}
}
stats := analyzeSearchResults(weaknesses)
printSearchStats(keyword, stats)
fmt.Println(strings.Repeat("-", 50))
}
}
func createLargeRegistry() *cwe.CWERegistry {
registry := cwe.NewCWERegistry()
testData := []*cwe.CWEWeakness{
{ID: "79", Name: "跨站脚本", Description: "应用程序在生成网页时未正确验证输入", Severity: "Medium"},
{ID: "89", Name: "SQL注入", Description: "应用程序在构造SQL命令时未正确验证输入", Severity: "High"},
{ID: "78", Name: "OS命令注入", Description: "应用程序在构造操作系统命令时未正确验证输入", Severity: "High"},
{ID: "77", Name: "路径遍历", Description: "应用程序未正确验证文件路径", Severity: "Medium"},
{ID: "352", Name: "跨站请求伪造", Description: "应用程序未验证请求来源", Severity: "Medium"},
{ID: "434", Name: "文件上传", Description: "应用程序未验证上传文件", Severity: "High"},
{ID: "20", Name: "输入验证不当", Description: "产品未正确验证输入", Severity: "Low"},
{ID: "95", Name: "代码注入", Description: "应用程序执行未验证的代码", Severity: "Critical"},
}
for _, weakness := range testData {
registry.AddCWE(weakness)
}
return registry
}
运行示例
保存任意示例代码为 main.go
,然后运行:
bash
go mod init cwe-search-example
go get github.com/scagogogo/cwe
go run main.go
最佳实践
- 搜索优化 - 对于大量数据,考虑建立索引
- 模糊匹配 - 实现容错的搜索算法
- 结果排序 - 按相关性对搜索结果排序
- 缓存结果 - 缓存常用搜索结果
- 用户体验 - 提供搜索建议和自动完成