搜索和工具
搜索和工具模块提供了强大的CWE数据搜索、过滤和实用功能。
概述
搜索和工具功能包括:
- 关键字搜索
- 高级过滤
- 数据验证
- 格式转换
- 实用工具函数
搜索功能
基本关键字搜索
go
// 在注册表中搜索
registry := cwe.NewCWERegistry()
// 添加一些测试数据
registry.AddCWE(&cwe.CWEWeakness{
ID: "79",
Name: "跨站脚本",
Description: "应用程序在生成网页时未正确验证输入",
})
registry.AddCWE(&cwe.CWEWeakness{
ID: "89",
Name: "SQL注入",
Description: "应用程序在构造SQL命令时未正确验证输入",
})
// 搜索包含"注入"的CWE
results := registry.SearchByKeyword("注入")
fmt.Printf("找到 %d 个结果\n", len(results))
高级搜索
go
// 自定义搜索函数
func advancedSearch(registry *cwe.CWERegistry, criteria SearchCriteria) []interface{} {
var results []interface{}
allData := registry.GetAll()
for _, item := range allData {
if matchesCriteria(item, criteria) {
results = append(results, item)
}
}
return results
}
type SearchCriteria struct {
Keywords []string
Severity string
Type string // "weakness", "category", "view"
IDRange *IDRange
NameLength *LengthRange
}
type IDRange struct {
Min, Max int
}
type LengthRange struct {
Min, Max int
}
func matchesCriteria(item interface{}, criteria SearchCriteria) bool {
// 类型过滤
if criteria.Type != "" {
switch criteria.Type {
case "weakness":
if _, ok := item.(*cwe.CWEWeakness); !ok {
return false
}
case "category":
if _, ok := item.(*cwe.CWECategory); !ok {
return false
}
case "view":
if _, ok := item.(*cwe.CWEView); !ok {
return false
}
}
}
// 关键字匹配
if len(criteria.Keywords) > 0 {
text := getSearchableText(item)
for _, keyword := range criteria.Keywords {
if !strings.Contains(strings.ToLower(text), strings.ToLower(keyword)) {
return false
}
}
}
// 严重程度过滤(仅适用于弱点)
if criteria.Severity != "" {
if weakness, ok := item.(*cwe.CWEWeakness); ok {
if weakness.Severity != criteria.Severity {
return false
}
}
}
return true
}
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 ""
}
}
过滤功能
按类型过滤
go
func filterByType(registry *cwe.CWERegistry, cweType string) []interface{} {
switch cweType {
case "weakness":
weaknesses := registry.GetWeaknesses()
result := make([]interface{}, len(weaknesses))
for i, w := range weaknesses {
result[i] = w
}
return result
case "category":
categories := registry.GetCategories()
result := make([]interface{}, len(categories))
for i, c := range categories {
result[i] = c
}
return result
case "view":
views := registry.GetViews()
result := make([]interface{}, len(views))
for i, v := range views {
result[i] = v
}
return result
default:
return registry.GetAll()
}
}
按严重程度过滤
go
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
}
// 使用示例
highSeverityWeaknesses := filterBySeverity(registry, "High")
mediumSeverityWeaknesses := filterBySeverity(registry, "Medium")
lowSeverityWeaknesses := filterBySeverity(registry, "Low")
按ID范围过滤
go
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
}
数据验证
CWE数据验证
go
func validateCWEWeakness(weakness *cwe.CWEWeakness) []string {
var errors []string
if weakness.ID == "" {
errors = append(errors, "ID不能为空")
}
if weakness.Name == "" {
errors = append(errors, "名称不能为空")
}
if len(weakness.Name) > 200 {
errors = append(errors, "名称过长(超过200字符)")
}
if weakness.Description == "" {
errors = append(errors, "描述不能为空")
}
if weakness.Severity != "" {
validSeverities := []string{"Low", "Medium", "High", "Critical"}
if !contains(validSeverities, weakness.Severity) {
errors = append(errors, "无效的严重程度")
}
}
return errors
}
func contains(slice []string, item string) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}
批量验证
go
func validateRegistry(registry *cwe.CWERegistry) map[string][]string {
validationErrors := make(map[string][]string)
// 验证弱点
weaknesses := registry.GetWeaknesses()
for _, weakness := range weaknesses {
errors := validateCWEWeakness(weakness)
if len(errors) > 0 {
validationErrors["CWE-"+weakness.ID] = errors
}
}
// 验证类别
categories := registry.GetCategories()
for _, category := range categories {
errors := validateCWECategory(category)
if len(errors) > 0 {
validationErrors["Category-"+category.ID] = errors
}
}
return validationErrors
}
func validateCWECategory(category *cwe.CWECategory) []string {
var errors []string
if category.ID == "" {
errors = append(errors, "ID不能为空")
}
if category.Name == "" {
errors = append(errors, "名称不能为空")
}
return errors
}
格式转换
ID格式化
go
func normalizeID(id string) string {
// 移除CWE-前缀
id = strings.TrimPrefix(strings.ToUpper(id), "CWE-")
// 移除前导零
id = strings.TrimLeft(id, "0")
// 如果为空,返回"0"
if id == "" {
return "0"
}
return id
}
func formatID(id string) string {
normalized := normalizeID(id)
return "CWE-" + normalized
}
// 使用示例
fmt.Println(formatID("79")) // CWE-79
fmt.Println(formatID("CWE-89")) // CWE-89
fmt.Println(formatID("0020")) // CWE-20
文本格式化
go
func formatDescription(description string, maxLength int) string {
if len(description) <= maxLength {
return description
}
// 截断并添加省略号
return description[:maxLength-3] + "..."
}
func formatName(name string) string {
// 首字母大写
if len(name) == 0 {
return name
}
return strings.ToUpper(string(name[0])) + strings.ToLower(name[1:])
}
统计工具
数据统计
go
func generateStatistics(registry *cwe.CWERegistry) map[string]interface{} {
stats := make(map[string]interface{})
// 基本计数
stats["total_count"] = registry.Count()
stats["weakness_count"] = len(registry.GetWeaknesses())
stats["category_count"] = len(registry.GetCategories())
stats["view_count"] = len(registry.GetViews())
// 严重程度分布
severityDist := make(map[string]int)
weaknesses := registry.GetWeaknesses()
for _, weakness := range weaknesses {
if weakness.Severity != "" {
severityDist[weakness.Severity]++
} else {
severityDist["Unknown"]++
}
}
stats["severity_distribution"] = severityDist
// 名称长度统计
nameLengths := make([]int, 0, len(weaknesses))
for _, weakness := range weaknesses {
nameLengths = append(nameLengths, len(weakness.Name))
}
if len(nameLengths) > 0 {
sort.Ints(nameLengths)
stats["name_length_min"] = nameLengths[0]
stats["name_length_max"] = nameLengths[len(nameLengths)-1]
stats["name_length_avg"] = average(nameLengths)
stats["name_length_median"] = median(nameLengths)
}
return stats
}
func average(numbers []int) float64 {
if len(numbers) == 0 {
return 0
}
sum := 0
for _, num := range numbers {
sum += num
}
return float64(sum) / float64(len(numbers))
}
func median(numbers []int) float64 {
if len(numbers) == 0 {
return 0
}
mid := len(numbers) / 2
if len(numbers)%2 == 0 {
return float64(numbers[mid-1]+numbers[mid]) / 2
}
return float64(numbers[mid])
}
导出工具
导出为不同格式
go
func exportToCSV(registry *cwe.CWERegistry, 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{"ID", "Type", "Name", "Description", "Severity"}
if err := writer.Write(headers); err != nil {
return err
}
// 写入数据
allData := registry.GetAll()
for _, item := range allData {
record := formatForCSV(item)
if err := writer.Write(record); err != nil {
return err
}
}
return nil
}
func formatForCSV(item interface{}) []string {
switch data := item.(type) {
case *cwe.CWEWeakness:
return []string{
data.ID,
"Weakness",
data.Name,
data.Description,
data.Severity,
}
case *cwe.CWECategory:
return []string{
data.ID,
"Category",
data.Name,
data.Description,
"",
}
case *cwe.CWEView:
return []string{
data.ID,
"View",
data.Name,
data.Description,
"",
}
default:
return []string{"", "", "", "", ""}
}
}
最佳实践
- 搜索优化 - 对于大量数据,考虑使用索引
- 数据验证 - 在处理数据前进行验证
- 错误处理 - 处理搜索和过滤中的错误
- 性能考虑 - 对于复杂搜索,考虑并发处理
- 用户体验 - 提供搜索进度和结果统计