parser.go
1 // Copyright (c) 2024-2026 Tencent Zhuque Lab. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // Requirement: Any integration or derivative work must explicitly attribute 16 // Tencent Zhuque Lab (https://github.com/Tencent/AI-Infra-Guard) in its 17 // documentation or user interface, as detailed in the NOTICE file. 18 19 // Package parser 实现了指纹规则的解析和评估功能。 20 // 该包提供了将YAML格式的指纹规则转换为可执行规则对象的功能, 21 // 并支持对HTTP请求响应进行指纹匹配评估。 22 package parser 23 24 import ( 25 "fmt" 26 27 "gopkg.in/yaml.v2" 28 ) 29 30 // FingerPrintInfo 定义了指纹的基本信息 31 type FingerPrintInfo struct { 32 Name string `yaml:"name" json:"name"` 33 Author string `yaml:"author" json:"author"` 34 Example []string `yaml:"example,omitempty" json:"example,omitempty"` 35 Desc string `yaml:"desc,omitempty" json:"desc,omitempty"` 36 Severity string `yaml:"severity" json:"severity"` 37 Metadata map[string]string `yaml:"metadata" json:"metadata"` 38 Recommendation int `yaml:"recommendation,omitempty" json:"recommendation,omitempty"` 39 } 40 41 // Extractor 定义了从响应中提取信息的规则 42 type Extractor struct { 43 Part string `yaml:"part" json:"part"` 44 Group string `yaml:"group" json:"group"` 45 Regex string `yaml:"regex" json:"regex"` 46 } 47 48 // HttpRule 定义了HTTP请求匹配规则 49 type HttpRule struct { 50 Method string `yaml:"method" json:"method"` 51 Path string `yaml:"path" json:"path"` 52 Matchers []string `yaml:"matchers" json:"matchers"` 53 Data string `yaml:"data,omitempty" json:"data,omitempty"` 54 dsl []*Rule `yaml:"-" json:"-"` 55 VersionRange string `yaml:"versionrange,omitempty" json:"versionrange,omitempty"` 56 Extractor Extractor `yaml:"extractor,omitempty" json:"extractor,omitempty"` 57 } 58 59 // GetDsl 返回解析后的DSL规则列表 60 func (h *HttpRule) GetDsl() []*Rule { 61 return h.dsl 62 } 63 64 // FingerPrint 定义了完整的指纹规则结构 65 type FingerPrint struct { 66 Info FingerPrintInfo `yaml:"info" json:"info"` 67 Http []HttpRule `yaml:"http" json:"http"` 68 Version []HttpRule `yaml:"version,omitempty" json:"version,omitempty"` 69 } 70 71 // FingerPrints 表示多个指纹规则的集合 72 type FingerPrints []FingerPrint 73 74 // Config 定义了进行指纹匹配时需要的配置信息 75 type Config struct { 76 Body string 77 Header string 78 Icon int32 79 Hash string 80 } 81 82 // AdvisoryConfig 提供漏洞配置信息 83 type AdvisoryConfig struct { 84 Version string 85 IsInternal bool 86 } 87 88 // transfromRule 将规则字符串转换为规则对象 89 // 参数: 90 // - rule: 规则字符串 91 // 92 // 返回: 93 // - *Rule: 解析后的规则对象 94 // - error: 解析过程中的错误 95 func transfromRule(rule string) (*Rule, error) { 96 tokens, err := ParseTokens(rule) 97 if err != nil { 98 return nil, err 99 } 100 if err = CheckBalance(tokens); err != nil { 101 return nil, err 102 } 103 return TransFormExp(tokens) 104 } 105 106 // InitFingerPrintFromData 从字节数据初始化指纹配置 107 // 参数: 108 // - reader: 包含YAML格式指纹配置的字节数据 109 // 110 // 返回: 111 // - *FingerPrint: 解析后的指纹对象 112 // - error: 解析过程中的错误 113 func InitFingerPrintFromData(reader []byte) (*FingerPrint, error) { 114 var fp FingerPrint 115 err := yaml.Unmarshal(reader, &fp) 116 if err != nil { 117 return nil, err 118 } 119 if err := compileMatchers(fp.Http); err != nil { 120 return nil, err 121 } 122 if err := compileMatchers(fp.Version); err != nil { 123 return nil, err 124 } 125 return &fp, err 126 } 127 128 // compileMatchers compiles textual matchers into executable DSL rules. 129 func compileMatchers(rules []HttpRule) error { 130 for i := range rules { 131 dsls := make([]*Rule, 0, len(rules[i].Matchers)) 132 hasHashMatcher := false 133 hasNonHashMatcher := false 134 for _, matcher := range rules[i].Matchers { 135 dsl, err := transfromRule(matcher) 136 if err != nil { 137 return err 138 } 139 usesHash, hashOnly := dsl.hashUsage() 140 if usesHash { 141 if !hashOnly { 142 return fmt.Errorf("hash matcher cannot be combined with other fields: %s %s -> %s", rules[i].Method, rules[i].Path, matcher) 143 } 144 hasHashMatcher = true 145 } else { 146 hasNonHashMatcher = true 147 } 148 dsls = append(dsls, dsl) 149 } 150 if hasHashMatcher && hasNonHashMatcher { 151 return fmt.Errorf("hash matcher cannot coexist with other matcher types: %s %s", rules[i].Method, rules[i].Path) 152 } 153 rules[i].dsl = dsls 154 } 155 return nil 156 } 157 158 // FpResult 指纹结构体 159 type FpResult struct { 160 Name string `json:"name"` 161 Version string `json:"version,omitempty"` 162 } 163 164 // Eval 评估配置是否匹配规则 165 // 参数: 166 // - config: 配置对象,包含请求体、请求头和图标信息 167 // - dsl: 要评估的规则对象 168 // 169 // 返回: 170 // - bool: 是否匹配规则 171 func Eval(config *Config, dsl *Rule) bool { 172 return dsl.Eval(config) 173 }