github.com/crowdsecurity/crowdsec@v1.6.1/pkg/types/appsec_event.go (about)

     1  package types
     2  
     3  import (
     4  	"regexp"
     5  	"slices"
     6  
     7  	log "github.com/sirupsen/logrus"
     8  )
     9  
    10  /*
    11   1. If user triggered a rule that is for a CVE, that has high confidence and that is blocking, ban
    12   2. If user triggered 3 distinct rules with medium confidence across 3 different requests, ban
    13  
    14  
    15  any(evt.Waf.ByTag("CVE"), {.confidence == "high" && .action == "block"})
    16  
    17  len(evt.Waf.ByTagRx("*CVE*").ByConfidence("high").ByAction("block")) > 1
    18  
    19  */
    20  
    21  type MatchedRules []map[string]interface{}
    22  
    23  type AppsecEvent struct {
    24  	HasInBandMatches, HasOutBandMatches bool
    25  	MatchedRules
    26  	Vars map[string]string
    27  }
    28  type Field string
    29  
    30  func (f Field) String() string {
    31  	return string(f)
    32  }
    33  
    34  const (
    35  	ID         Field = "id"
    36  	RuleType   Field = "rule_type"
    37  	Tags       Field = "tags"
    38  	File       Field = "file"
    39  	Confidence Field = "confidence"
    40  	Revision   Field = "revision"
    41  	SecMark    Field = "secmark"
    42  	Accuracy   Field = "accuracy"
    43  	Msg        Field = "msg"
    44  	Severity   Field = "severity"
    45  	Kind       Field = "kind"
    46  )
    47  
    48  func (w AppsecEvent) GetVar(varName string) string {
    49  	if w.Vars == nil {
    50  		return ""
    51  	}
    52  	if val, ok := w.Vars[varName]; ok {
    53  		return val
    54  	}
    55  	log.Infof("var %s not found. Available variables: %+v", varName, w.Vars)
    56  	return ""
    57  
    58  }
    59  
    60  // getters
    61  func (w MatchedRules) GetField(field Field) []interface{} {
    62  	ret := make([]interface{}, 0)
    63  	for _, rule := range w {
    64  		ret = append(ret, rule[field.String()])
    65  	}
    66  	return ret
    67  }
    68  
    69  func (w MatchedRules) GetURI() string {
    70  	for _, rule := range w {
    71  		return rule["uri"].(string)
    72  	}
    73  	return ""
    74  }
    75  
    76  func (w MatchedRules) GetHash() string {
    77  	for _, rule := range w {
    78  		//@sbl : let's fix this
    79  		return rule["hash"].(string)
    80  	}
    81  	return ""
    82  }
    83  
    84  func (w MatchedRules) GetVersion() string {
    85  	for _, rule := range w {
    86  		//@sbl : let's fix this
    87  		return rule["version"].(string)
    88  	}
    89  	return ""
    90  }
    91  
    92  func (w MatchedRules) GetName() string {
    93  	for _, rule := range w {
    94  		//@sbl : let's fix this
    95  		return rule["name"].(string)
    96  	}
    97  	return ""
    98  }
    99  
   100  func (w MatchedRules) GetMethod() string {
   101  	for _, rule := range w {
   102  		return rule["method"].(string)
   103  	}
   104  	return ""
   105  }
   106  
   107  func (w MatchedRules) GetRuleIDs() []int {
   108  	ret := make([]int, 0)
   109  	for _, rule := range w {
   110  		ret = append(ret, rule["id"].(int))
   111  	}
   112  	return ret
   113  }
   114  
   115  func (w MatchedRules) Kinds() []string {
   116  	ret := make([]string, 0)
   117  	for _, rule := range w {
   118  		exists := false
   119  		for _, val := range ret {
   120  			if val == rule["kind"] {
   121  				exists = true
   122  				break
   123  			}
   124  		}
   125  		if !exists {
   126  			ret = append(ret, rule["kind"].(string))
   127  		}
   128  	}
   129  	return ret
   130  }
   131  
   132  func (w MatchedRules) GetMatchedZones() []string {
   133  	ret := make([]string, 0)
   134  
   135  	for _, rule := range w {
   136  		for _, zone := range rule["matched_zones"].([]string) {
   137  			if !slices.Contains(ret, zone) {
   138  				ret = append(ret, zone)
   139  			}
   140  		}
   141  	}
   142  	return ret
   143  }
   144  
   145  // filters
   146  func (w MatchedRules) ByID(id int) MatchedRules {
   147  	ret := MatchedRules{}
   148  
   149  	for _, rule := range w {
   150  		if rule["id"] == id {
   151  			ret = append(ret, rule)
   152  		}
   153  	}
   154  	return ret
   155  }
   156  
   157  func (w MatchedRules) ByKind(kind string) MatchedRules {
   158  	ret := MatchedRules{}
   159  	for _, rule := range w {
   160  		if rule["kind"] == kind {
   161  			ret = append(ret, rule)
   162  		}
   163  	}
   164  	return ret
   165  }
   166  
   167  func (w MatchedRules) ByTags(match []string) MatchedRules {
   168  	ret := MatchedRules{}
   169  	for _, rule := range w {
   170  		for _, tag := range rule["tags"].([]string) {
   171  			for _, match_tag := range match {
   172  				if tag == match_tag {
   173  					ret = append(ret, rule)
   174  					break
   175  				}
   176  			}
   177  		}
   178  	}
   179  	return ret
   180  }
   181  
   182  func (w MatchedRules) ByTag(match string) MatchedRules {
   183  	ret := MatchedRules{}
   184  	for _, rule := range w {
   185  		for _, tag := range rule["tags"].([]string) {
   186  			if tag == match {
   187  				ret = append(ret, rule)
   188  				break
   189  			}
   190  		}
   191  	}
   192  	return ret
   193  }
   194  
   195  func (w MatchedRules) ByTagRx(rx string) MatchedRules {
   196  	ret := MatchedRules{}
   197  	re := regexp.MustCompile(rx)
   198  	if re == nil {
   199  		return ret
   200  	}
   201  	for _, rule := range w {
   202  		for _, tag := range rule["tags"].([]string) {
   203  			log.Debugf("ByTagRx: %s = %s -> %t", rx, tag, re.MatchString(tag))
   204  			if re.MatchString(tag) {
   205  				ret = append(ret, rule)
   206  				break
   207  			}
   208  		}
   209  	}
   210  	return ret
   211  }
   212  
   213  func (w MatchedRules) ByDisruptiveness(is bool) MatchedRules {
   214  	ret := MatchedRules{}
   215  	for _, rule := range w {
   216  		if rule["disruptive"] == is {
   217  			ret = append(ret, rule)
   218  		}
   219  	}
   220  	log.Debugf("ByDisruptiveness(%t) -> %d", is, len(ret))
   221  
   222  	return ret
   223  }
   224  
   225  func (w MatchedRules) BySeverity(severity string) MatchedRules {
   226  	ret := MatchedRules{}
   227  	for _, rule := range w {
   228  		if rule["severity"] == severity {
   229  			ret = append(ret, rule)
   230  		}
   231  	}
   232  	log.Debugf("BySeverity(%s) -> %d", severity, len(ret))
   233  	return ret
   234  }
   235  
   236  func (w MatchedRules) ByAccuracy(accuracy string) MatchedRules {
   237  	ret := MatchedRules{}
   238  	for _, rule := range w {
   239  		if rule["accuracy"] == accuracy {
   240  			ret = append(ret, rule)
   241  		}
   242  	}
   243  	log.Debugf("ByAccuracy(%s) -> %d", accuracy, len(ret))
   244  	return ret
   245  }