diff --git a/pkg/waf/waap_rule/modsec_rule_test.go b/pkg/waf/waap_rule/modsec_rule_test.go index 62e04d8e1..2232540ec 100644 --- a/pkg/waf/waap_rule/modsec_rule_test.go +++ b/pkg/waf/waap_rule/modsec_rule_test.go @@ -16,7 +16,7 @@ func TestVPatchRuleString(t *testing.T) { Match: match{Type: "regex", Value: "[^a-zA-Z]"}, Transform: []string{"lowercase"}, }, - expected: `SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:1136235475,phase:2,deny,log,msg:'Base Rule',t:lowercase"`, + expected: `SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:2203944045,phase:2,deny,log,msg:'Base Rule',tag:'crowdsec-Base Rule',t:lowercase"`, }, { name: "Multiple Zones", @@ -26,7 +26,7 @@ func TestVPatchRuleString(t *testing.T) { Match: match{Type: "regex", Value: "[^a-zA-Z]"}, Transform: []string{"lowercase"}, }, - expected: `SecRule ARGS_GET:foo|ARGS_POST:foo "@rx [^a-zA-Z]" "id:2088895799,phase:2,deny,log,msg:'Multiple Zones',t:lowercase"`, + expected: `SecRule ARGS_GET:foo|ARGS_POST:foo "@rx [^a-zA-Z]" "id:3387135861,phase:2,deny,log,msg:'Multiple Zones',tag:'crowdsec-Multiple Zones',t:lowercase"`, }, { name: "Basic AND", @@ -47,8 +47,8 @@ func TestVPatchRuleString(t *testing.T) { }, }, }, - expected: `SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:2323451654,phase:2,deny,log,msg:'Basic AND_and_0',t:lowercase,chain" -SecRule ARGS_GET:bar "@rx [^a-zA-Z]" "id:2075918819,phase:2,deny,log,msg:'Basic AND_and_1',t:lowercase"`, + expected: `SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:4145519614,phase:2,deny,log,msg:'Basic AND',tag:'crowdsec-Basic AND',t:lowercase,chain" +SecRule ARGS_GET:bar "@rx [^a-zA-Z]" "id:1865217529,phase:2,deny,log,msg:'Basic AND',tag:'crowdsec-Basic AND',t:lowercase"`, }, { name: "Basic OR", @@ -68,8 +68,8 @@ SecRule ARGS_GET:bar "@rx [^a-zA-Z]" "id:2075918819,phase:2,deny,log,msg:'Basic }, }, }, - expected: `SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:2720972114,phase:2,deny,log,msg:'Basic OR_or_0',t:lowercase,skip:1" -SecRule ARGS_GET:bar "@rx [^a-zA-Z]" "id:2638639999,phase:2,deny,log,msg:'Basic OR_or_1',t:lowercase"`, + expected: `SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:651140804,phase:2,deny,log,msg:'Basic OR',tag:'crowdsec-Basic OR',t:lowercase,skip:1" +SecRule ARGS_GET:bar "@rx [^a-zA-Z]" "id:271441587,phase:2,deny,log,msg:'Basic OR',tag:'crowdsec-Basic OR',t:lowercase"`, }, { name: "OR AND mix", @@ -97,8 +97,9 @@ SecRule ARGS_GET:bar "@rx [^a-zA-Z]" "id:2638639999,phase:2,deny,log,msg:'Basic }, }, }, - expected: `SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:2720972114,phase:2,deny,log,msg:'Basic OR_or_0',t:lowercase,skip:1" -SecRule ARGS_GET:bar "@rx [^a-zA-Z]" "id:2638639999,phase:2,deny,log,msg:'Basic OR_or_1',t:lowercase"`, + expected: `SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:1714963250,phase:2,deny,log,msg:'OR AND mix',tag:'crowdsec-OR AND mix',t:lowercase,skip:1" +SecRule ARGS_GET:bar "@rx [^a-zA-Z]" "id:1519945803,phase:2,deny,log,msg:'OR AND mix',tag:'crowdsec-OR AND mix',t:lowercase" +SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:1519945803,phase:2,deny,log,msg:'OR AND mix',tag:'crowdsec-OR AND mix',t:lowercase"`, }, } diff --git a/pkg/waf/waap_rule/modsecurity.go b/pkg/waf/waap_rule/modsecurity.go index 8b3ab9f9f..7060ebf1f 100644 --- a/pkg/waf/waap_rule/modsecurity.go +++ b/pkg/waf/waap_rule/modsecurity.go @@ -52,7 +52,7 @@ var bodyTypeMatch map[string]string = map[string]string{ func (m *ModsecurityRule) Build(rule *CustomRule, waapRuleName string) (string, []uint32, error) { - rules, err := m.buildRules(rule, waapRuleName, false, 0) + rules, err := m.buildRules(rule, waapRuleName, false, 0, 0) if err != nil { return "", nil, err @@ -62,11 +62,12 @@ func (m *ModsecurityRule) Build(rule *CustomRule, waapRuleName string) (string, return strings.Join(rules, "\n"), m.ids, nil } -func (m *ModsecurityRule) generateRuleID(rule *CustomRule, waapRuleName string) uint32 { +func (m *ModsecurityRule) generateRuleID(rule *CustomRule, waapRuleName string, depth int) uint32 { h := fnv.New32a() h.Write([]byte(waapRuleName)) h.Write([]byte(rule.Match.Type)) h.Write([]byte(rule.Match.Value)) + h.Write([]byte(fmt.Sprintf("%d", depth))) for _, zone := range rule.Zones { h.Write([]byte(zone)) } @@ -78,14 +79,15 @@ func (m *ModsecurityRule) generateRuleID(rule *CustomRule, waapRuleName string) return id } -func (m *ModsecurityRule) buildRules(rule *CustomRule, waapRuleName string, and bool, toSkip int) ([]string, error) { +func (m *ModsecurityRule) buildRules(rule *CustomRule, waapRuleName string, and bool, toSkip int, depth int) ([]string, error) { ret := make([]string, 0) if rule.And != nil { for c, andRule := range rule.And { - subName := fmt.Sprintf("%s_and_%d", waapRuleName, c) + depth++ + //subName := fmt.Sprintf("%s_and_%d", waapRuleName, c) lastRule := c == len(rule.And)-1 // || len(rule.Or) == 0 - rules, err := m.buildRules(&andRule, subName, !lastRule, 0) + rules, err := m.buildRules(&andRule, waapRuleName, !lastRule, 0, depth) if err != nil { return nil, err } @@ -95,9 +97,10 @@ func (m *ModsecurityRule) buildRules(rule *CustomRule, waapRuleName string, and if rule.Or != nil { for c, orRule := range rule.Or { - subName := fmt.Sprintf("%s_or_%d", waapRuleName, c) + depth++ + //subName := fmt.Sprintf("%s_or_%d", waapRuleName, c) skip := len(rule.Or) - c - 1 - rules, err := m.buildRules(&orRule, subName, false, skip) + rules, err := m.buildRules(&orRule, waapRuleName, false, skip, depth) if err != nil { return nil, err } @@ -140,7 +143,7 @@ func (m *ModsecurityRule) buildRules(rule *CustomRule, waapRuleName string, and } //Should phase:2 be configurable? - r.WriteString(fmt.Sprintf(` "id:%d,phase:2,deny,log,msg:'%s'`, m.generateRuleID(rule, waapRuleName), waapRuleName)) + r.WriteString(fmt.Sprintf(` "id:%d,phase:2,deny,log,msg:'%s',tag:'crowdsec-%s'`, m.generateRuleID(rule, waapRuleName, depth), waapRuleName, waapRuleName)) if rule.Transform != nil { for _, transform := range rule.Transform { diff --git a/pkg/waf/waf_helpers.go b/pkg/waf/waf_helpers.go index 968d8deca..a97af1e81 100644 --- a/pkg/waf/waf_helpers.go +++ b/pkg/waf/waf_helpers.go @@ -34,10 +34,10 @@ func GetExprWAFOptions(ctx map[string]interface{}) []expr.Option { func GetOnLoadEnv(w *WaapRuntimeConfig) map[string]interface{} { //FIXME: use expr.Function instead of this return map[string]interface{}{ - "DisableInBandRuleByID": w.DisableInBandRuleByID, - "DisableOutBandRuleByID": w.DisableOutBandRuleByID, - "DisableInBandRuleByTag": w.DisableInBandRuleByTag, - "DisableOutBandRuleByTag": w.DisableOutBandRuleByTag, + "RemoveInBandRuleByID": w.DisableInBandRuleByID, + "RemoveOutBandRuleByID": w.DisableOutBandRuleByID, + "RemoveInBandRuleByTag": w.DisableInBandRuleByTag, + "RemoveOutBandRuleByTag": w.DisableOutBandRuleByTag, } }