github.com/crowdsecurity/crowdsec@v1.6.1/pkg/acquisition/modules/appsec/appsec_remediation_test.go (about) 1 package appsecacquisition 2 3 import ( 4 "net/http" 5 "net/url" 6 "testing" 7 8 "github.com/crowdsecurity/crowdsec/pkg/appsec" 9 "github.com/crowdsecurity/crowdsec/pkg/appsec/appsec_rule" 10 "github.com/crowdsecurity/crowdsec/pkg/types" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func TestAppsecDefaultPassRemediation(t *testing.T) { 15 16 tests := []appsecRuleTest{ 17 { 18 name: "Basic non-matching rule", 19 expected_load_ok: true, 20 inband_rules: []appsec_rule.CustomRule{ 21 { 22 Name: "rule1", 23 Zones: []string{"ARGS"}, 24 Variables: []string{"foo"}, 25 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 26 Transform: []string{"lowercase"}, 27 }, 28 }, 29 input_request: appsec.ParsedRequest{ 30 RemoteAddr: "1.2.3.4", 31 Method: "GET", 32 URI: "/", 33 Args: url.Values{"foo": []string{"tutu"}}, 34 }, 35 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 36 require.Equal(t, appsec.AllowRemediation, responses[0].Action) 37 require.Equal(t, http.StatusOK, statusCode) 38 require.Equal(t, appsec.AllowRemediation, appsecResponse.Action) 39 require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus) 40 }, 41 }, 42 { 43 name: "DefaultPassAction: pass", 44 expected_load_ok: true, 45 inband_rules: []appsec_rule.CustomRule{ 46 { 47 Name: "rule1", 48 Zones: []string{"ARGS"}, 49 Variables: []string{"foo"}, 50 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 51 Transform: []string{"lowercase"}, 52 }, 53 }, 54 input_request: appsec.ParsedRequest{ 55 RemoteAddr: "1.2.3.4", 56 Method: "GET", 57 URI: "/", 58 Args: url.Values{"foo": []string{"tutu"}}, 59 }, 60 DefaultPassAction: "allow", 61 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 62 require.Equal(t, appsec.AllowRemediation, responses[0].Action) 63 require.Equal(t, http.StatusOK, statusCode) 64 require.Equal(t, appsec.AllowRemediation, appsecResponse.Action) 65 require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus) 66 }, 67 }, 68 { 69 name: "DefaultPassAction: captcha", 70 expected_load_ok: true, 71 inband_rules: []appsec_rule.CustomRule{ 72 { 73 Name: "rule1", 74 Zones: []string{"ARGS"}, 75 Variables: []string{"foo"}, 76 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 77 Transform: []string{"lowercase"}, 78 }, 79 }, 80 input_request: appsec.ParsedRequest{ 81 RemoteAddr: "1.2.3.4", 82 Method: "GET", 83 URI: "/", 84 Args: url.Values{"foo": []string{"tutu"}}, 85 }, 86 DefaultPassAction: "captcha", 87 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 88 require.Equal(t, appsec.CaptchaRemediation, responses[0].Action) 89 require.Equal(t, http.StatusOK, statusCode) //@tko: body is captcha, but as it's 200, captcha won't be showed to user 90 require.Equal(t, appsec.CaptchaRemediation, appsecResponse.Action) 91 require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus) 92 }, 93 }, 94 { 95 name: "DefaultPassHTTPCode: 200", 96 expected_load_ok: true, 97 inband_rules: []appsec_rule.CustomRule{ 98 { 99 Name: "rule1", 100 Zones: []string{"ARGS"}, 101 Variables: []string{"foo"}, 102 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 103 Transform: []string{"lowercase"}, 104 }, 105 }, 106 input_request: appsec.ParsedRequest{ 107 RemoteAddr: "1.2.3.4", 108 Method: "GET", 109 URI: "/", 110 Args: url.Values{"foo": []string{"tutu"}}, 111 }, 112 UserPassedHTTPCode: 200, 113 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 114 require.Equal(t, appsec.AllowRemediation, responses[0].Action) 115 require.Equal(t, http.StatusOK, statusCode) 116 require.Equal(t, appsec.AllowRemediation, appsecResponse.Action) 117 require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus) 118 }, 119 }, 120 { 121 name: "DefaultPassHTTPCode: 200", 122 expected_load_ok: true, 123 inband_rules: []appsec_rule.CustomRule{ 124 { 125 Name: "rule1", 126 Zones: []string{"ARGS"}, 127 Variables: []string{"foo"}, 128 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 129 Transform: []string{"lowercase"}, 130 }, 131 }, 132 input_request: appsec.ParsedRequest{ 133 RemoteAddr: "1.2.3.4", 134 Method: "GET", 135 URI: "/", 136 Args: url.Values{"foo": []string{"tutu"}}, 137 }, 138 UserPassedHTTPCode: 418, 139 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 140 require.Equal(t, appsec.AllowRemediation, responses[0].Action) 141 require.Equal(t, http.StatusOK, statusCode) 142 require.Equal(t, appsec.AllowRemediation, appsecResponse.Action) 143 require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus) 144 }, 145 }, 146 } 147 for _, test := range tests { 148 t.Run(test.name, func(t *testing.T) { 149 loadAppSecEngine(test, t) 150 }) 151 } 152 } 153 154 func TestAppsecDefaultRemediation(t *testing.T) { 155 156 tests := []appsecRuleTest{ 157 { 158 name: "Basic matching rule", 159 expected_load_ok: true, 160 inband_rules: []appsec_rule.CustomRule{ 161 { 162 Name: "rule1", 163 Zones: []string{"ARGS"}, 164 Variables: []string{"foo"}, 165 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 166 Transform: []string{"lowercase"}, 167 }, 168 }, 169 input_request: appsec.ParsedRequest{ 170 RemoteAddr: "1.2.3.4", 171 Method: "GET", 172 URI: "/urllll", 173 Args: url.Values{"foo": []string{"toto"}}, 174 }, 175 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 176 require.Equal(t, appsec.BanRemediation, responses[0].Action) 177 require.Equal(t, http.StatusForbidden, statusCode) 178 require.Equal(t, appsec.BanRemediation, appsecResponse.Action) 179 require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus) 180 }, 181 }, 182 { 183 name: "default remediation to ban (default)", 184 expected_load_ok: true, 185 inband_rules: []appsec_rule.CustomRule{ 186 { 187 Name: "rule42", 188 Zones: []string{"ARGS"}, 189 Variables: []string{"foo"}, 190 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 191 Transform: []string{"lowercase"}, 192 }, 193 }, 194 input_request: appsec.ParsedRequest{ 195 RemoteAddr: "1.2.3.4", 196 Method: "GET", 197 URI: "/urllll", 198 Args: url.Values{"foo": []string{"toto"}}, 199 }, 200 DefaultRemediation: "ban", 201 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 202 require.Equal(t, appsec.BanRemediation, responses[0].Action) 203 require.Equal(t, http.StatusForbidden, statusCode) 204 require.Equal(t, appsec.BanRemediation, appsecResponse.Action) 205 require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus) 206 }, 207 }, 208 { 209 name: "default remediation to allow", 210 expected_load_ok: true, 211 inband_rules: []appsec_rule.CustomRule{ 212 { 213 Name: "rule42", 214 Zones: []string{"ARGS"}, 215 Variables: []string{"foo"}, 216 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 217 Transform: []string{"lowercase"}, 218 }, 219 }, 220 input_request: appsec.ParsedRequest{ 221 RemoteAddr: "1.2.3.4", 222 Method: "GET", 223 URI: "/urllll", 224 Args: url.Values{"foo": []string{"toto"}}, 225 }, 226 DefaultRemediation: "allow", 227 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 228 require.Equal(t, appsec.AllowRemediation, responses[0].Action) 229 require.Equal(t, http.StatusOK, statusCode) 230 require.Equal(t, appsec.AllowRemediation, appsecResponse.Action) 231 require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus) 232 }, 233 }, 234 { 235 name: "default remediation to captcha", 236 expected_load_ok: true, 237 inband_rules: []appsec_rule.CustomRule{ 238 { 239 Name: "rule42", 240 Zones: []string{"ARGS"}, 241 Variables: []string{"foo"}, 242 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 243 Transform: []string{"lowercase"}, 244 }, 245 }, 246 input_request: appsec.ParsedRequest{ 247 RemoteAddr: "1.2.3.4", 248 Method: "GET", 249 URI: "/urllll", 250 Args: url.Values{"foo": []string{"toto"}}, 251 }, 252 DefaultRemediation: "captcha", 253 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 254 require.Equal(t, appsec.CaptchaRemediation, responses[0].Action) 255 require.Equal(t, http.StatusForbidden, statusCode) 256 require.Equal(t, appsec.CaptchaRemediation, appsecResponse.Action) 257 require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus) 258 }, 259 }, 260 { 261 name: "custom user HTTP code", 262 expected_load_ok: true, 263 inband_rules: []appsec_rule.CustomRule{ 264 { 265 Name: "rule42", 266 Zones: []string{"ARGS"}, 267 Variables: []string{"foo"}, 268 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 269 Transform: []string{"lowercase"}, 270 }, 271 }, 272 input_request: appsec.ParsedRequest{ 273 RemoteAddr: "1.2.3.4", 274 Method: "GET", 275 URI: "/urllll", 276 Args: url.Values{"foo": []string{"toto"}}, 277 }, 278 UserBlockedHTTPCode: 418, 279 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 280 require.Equal(t, appsec.BanRemediation, responses[0].Action) 281 require.Equal(t, http.StatusForbidden, statusCode) 282 require.Equal(t, appsec.BanRemediation, appsecResponse.Action) 283 require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus) 284 }, 285 }, 286 { 287 name: "custom remediation + HTTP code", 288 expected_load_ok: true, 289 inband_rules: []appsec_rule.CustomRule{ 290 { 291 Name: "rule42", 292 Zones: []string{"ARGS"}, 293 Variables: []string{"foo"}, 294 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 295 Transform: []string{"lowercase"}, 296 }, 297 }, 298 input_request: appsec.ParsedRequest{ 299 RemoteAddr: "1.2.3.4", 300 Method: "GET", 301 URI: "/urllll", 302 Args: url.Values{"foo": []string{"toto"}}, 303 }, 304 UserBlockedHTTPCode: 418, 305 DefaultRemediation: "foobar", 306 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 307 require.Equal(t, "foobar", responses[0].Action) 308 require.Equal(t, http.StatusForbidden, statusCode) 309 require.Equal(t, "foobar", appsecResponse.Action) 310 require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus) 311 }, 312 }, 313 } 314 315 for _, test := range tests { 316 t.Run(test.name, func(t *testing.T) { 317 loadAppSecEngine(test, t) 318 }) 319 } 320 }