github.com/crowdsecurity/crowdsec@v1.6.1/pkg/appsec/appsec_rule/modsec_rule_test.go (about) 1 package appsec_rule 2 3 import "testing" 4 5 func TestVPatchRuleString(t *testing.T) { 6 tests := []struct { 7 name string 8 rule CustomRule 9 expected string 10 }{ 11 { 12 name: "Collection count", 13 rule: CustomRule{ 14 Zones: []string{"ARGS"}, 15 Variables: []string{"foo"}, 16 Match: Match{Type: "eq", Value: "1"}, 17 Transform: []string{"count"}, 18 }, 19 expected: `SecRule &ARGS_GET:foo "@eq 1" "id:853070236,phase:2,deny,log,msg:'Collection count',tag:'crowdsec-Collection count'"`, 20 }, 21 { 22 name: "Base Rule", 23 rule: CustomRule{ 24 Zones: []string{"ARGS"}, 25 Variables: []string{"foo"}, 26 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 27 Transform: []string{"lowercase"}, 28 }, 29 expected: `SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:2203944045,phase:2,deny,log,msg:'Base Rule',tag:'crowdsec-Base Rule',t:lowercase"`, 30 }, 31 { 32 name: "One zone, multi var", 33 rule: CustomRule{ 34 Zones: []string{"ARGS"}, 35 Variables: []string{"foo", "bar"}, 36 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 37 Transform: []string{"lowercase"}, 38 }, 39 expected: `SecRule ARGS_GET:foo|ARGS_GET:bar "@rx [^a-zA-Z]" "id:385719930,phase:2,deny,log,msg:'One zone, multi var',tag:'crowdsec-One zone, multi var',t:lowercase"`, 40 }, 41 { 42 name: "Base Rule #2", 43 rule: CustomRule{ 44 Zones: []string{"METHOD"}, 45 Match: Match{Type: "startsWith", Value: "toto"}, 46 }, 47 expected: `SecRule REQUEST_METHOD "@beginsWith toto" "id:2759779019,phase:2,deny,log,msg:'Base Rule #2',tag:'crowdsec-Base Rule #2'"`, 48 }, 49 { 50 name: "Base Negative Rule", 51 rule: CustomRule{ 52 Zones: []string{"METHOD"}, 53 Match: Match{Type: "startsWith", Value: "toto", Not: true}, 54 }, 55 expected: `SecRule REQUEST_METHOD "!@beginsWith toto" "id:3966251995,phase:2,deny,log,msg:'Base Negative Rule',tag:'crowdsec-Base Negative Rule'"`, 56 }, 57 { 58 name: "Multiple Zones", 59 rule: CustomRule{ 60 Zones: []string{"ARGS", "BODY_ARGS"}, 61 Variables: []string{"foo"}, 62 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 63 Transform: []string{"lowercase"}, 64 }, 65 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"`, 66 }, 67 { 68 name: "Multiple Zones Multi Var", 69 rule: CustomRule{ 70 Zones: []string{"ARGS", "BODY_ARGS"}, 71 Variables: []string{"foo", "bar"}, 72 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 73 Transform: []string{"lowercase"}, 74 }, 75 expected: `SecRule ARGS_GET:foo|ARGS_GET:bar|ARGS_POST:foo|ARGS_POST:bar "@rx [^a-zA-Z]" "id:1119773585,phase:2,deny,log,msg:'Multiple Zones Multi Var',tag:'crowdsec-Multiple Zones Multi Var',t:lowercase"`, 76 }, 77 { 78 name: "Multiple Zones No Vars", 79 rule: CustomRule{ 80 Zones: []string{"ARGS", "BODY_ARGS"}, 81 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 82 Transform: []string{"lowercase"}, 83 }, 84 expected: `SecRule ARGS_GET|ARGS_POST "@rx [^a-zA-Z]" "id:2020110336,phase:2,deny,log,msg:'Multiple Zones No Vars',tag:'crowdsec-Multiple Zones No Vars',t:lowercase"`, 85 }, 86 { 87 name: "Basic AND", 88 rule: CustomRule{ 89 And: []CustomRule{ 90 { 91 92 Zones: []string{"ARGS"}, 93 Variables: []string{"foo"}, 94 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 95 Transform: []string{"lowercase"}, 96 }, 97 { 98 Zones: []string{"ARGS"}, 99 Variables: []string{"bar"}, 100 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 101 Transform: []string{"lowercase"}, 102 }, 103 }, 104 }, 105 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" 106 SecRule ARGS_GET:bar "@rx [^a-zA-Z]" "id:1865217529,phase:2,deny,log,msg:'Basic AND',tag:'crowdsec-Basic AND',t:lowercase"`, 107 }, 108 { 109 name: "Basic OR", 110 rule: CustomRule{ 111 Or: []CustomRule{ 112 { 113 Zones: []string{"ARGS"}, 114 Variables: []string{"foo"}, 115 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 116 Transform: []string{"lowercase"}, 117 }, 118 { 119 Zones: []string{"ARGS"}, 120 Variables: []string{"bar"}, 121 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 122 Transform: []string{"lowercase"}, 123 }, 124 }, 125 }, 126 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" 127 SecRule ARGS_GET:bar "@rx [^a-zA-Z]" "id:271441587,phase:2,deny,log,msg:'Basic OR',tag:'crowdsec-Basic OR',t:lowercase"`, 128 }, 129 { 130 name: "OR AND mix", 131 rule: CustomRule{ 132 And: []CustomRule{ 133 { 134 Zones: []string{"ARGS"}, 135 Variables: []string{"foo"}, 136 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 137 Transform: []string{"lowercase"}, 138 Or: []CustomRule{ 139 { 140 Zones: []string{"ARGS"}, 141 Variables: []string{"foo"}, 142 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 143 Transform: []string{"lowercase"}, 144 }, 145 { 146 Zones: []string{"ARGS"}, 147 Variables: []string{"bar"}, 148 Match: Match{Type: "regex", Value: "[^a-zA-Z]"}, 149 Transform: []string{"lowercase"}, 150 }, 151 }, 152 }, 153 }, 154 }, 155 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" 156 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" 157 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"`, 158 }, 159 } 160 161 for _, tt := range tests { 162 t.Run(tt.name, func(t *testing.T) { 163 actual, _, err := tt.rule.Convert(ModsecurityRuleType, tt.name) 164 165 if err != nil { 166 t.Errorf("Error converting rule: %s", err) 167 } 168 if actual != tt.expected { 169 t.Errorf("Expected:\n%s\nGot:\n%s", tt.expected, actual) 170 } 171 }) 172 } 173 }