github.com/crowdsecurity/crowdsec@v1.6.1/pkg/acquisition/modules/appsec/appsec_rules_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 log "github.com/sirupsen/logrus" 12 "github.com/stretchr/testify/require" 13 ) 14 15 func TestAppsecRuleMatches(t *testing.T) { 16 17 tests := []appsecRuleTest{ 18 { 19 name: "Basic matching rule", 20 expected_load_ok: true, 21 inband_rules: []appsec_rule.CustomRule{ 22 { 23 Name: "rule1", 24 Zones: []string{"ARGS"}, 25 Variables: []string{"foo"}, 26 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 27 Transform: []string{"lowercase"}, 28 }, 29 }, 30 input_request: appsec.ParsedRequest{ 31 RemoteAddr: "1.2.3.4", 32 Method: "GET", 33 URI: "/urllll", 34 Args: url.Values{"foo": []string{"toto"}}, 35 }, 36 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 37 require.Len(t, events, 2) 38 require.Equal(t, types.APPSEC, events[0].Type) 39 40 require.Equal(t, types.LOG, events[1].Type) 41 require.True(t, events[1].Appsec.HasInBandMatches) 42 require.Len(t, events[1].Appsec.MatchedRules, 1) 43 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 44 45 require.Len(t, responses, 1) 46 require.True(t, responses[0].InBandInterrupt) 47 }, 48 }, 49 { 50 name: "Basic non-matching rule", 51 expected_load_ok: true, 52 inband_rules: []appsec_rule.CustomRule{ 53 { 54 Name: "rule1", 55 Zones: []string{"ARGS"}, 56 Variables: []string{"foo"}, 57 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 58 Transform: []string{"lowercase"}, 59 }, 60 }, 61 input_request: appsec.ParsedRequest{ 62 RemoteAddr: "1.2.3.4", 63 Method: "GET", 64 URI: "/urllll", 65 Args: url.Values{"foo": []string{"tutu"}}, 66 }, 67 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 68 require.Empty(t, events) 69 require.Len(t, responses, 1) 70 require.False(t, responses[0].InBandInterrupt) 71 require.False(t, responses[0].OutOfBandInterrupt) 72 }, 73 }, 74 { 75 name: "default remediation to allow", 76 expected_load_ok: true, 77 inband_rules: []appsec_rule.CustomRule{ 78 { 79 Name: "rule42", 80 Zones: []string{"ARGS"}, 81 Variables: []string{"foo"}, 82 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 83 Transform: []string{"lowercase"}, 84 }, 85 }, 86 input_request: appsec.ParsedRequest{ 87 RemoteAddr: "1.2.3.4", 88 Method: "GET", 89 URI: "/urllll", 90 Args: url.Values{"foo": []string{"toto"}}, 91 }, 92 DefaultRemediation: "allow", 93 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 94 require.Equal(t, appsec.AllowRemediation, responses[0].Action) 95 require.Equal(t, http.StatusOK, statusCode) 96 require.Equal(t, appsec.AllowRemediation, appsecResponse.Action) 97 require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus) 98 }, 99 }, 100 { 101 name: "default remediation to captcha", 102 expected_load_ok: true, 103 inband_rules: []appsec_rule.CustomRule{ 104 { 105 Name: "rule42", 106 Zones: []string{"ARGS"}, 107 Variables: []string{"foo"}, 108 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 109 Transform: []string{"lowercase"}, 110 }, 111 }, 112 input_request: appsec.ParsedRequest{ 113 RemoteAddr: "1.2.3.4", 114 Method: "GET", 115 URI: "/urllll", 116 Args: url.Values{"foo": []string{"toto"}}, 117 }, 118 DefaultRemediation: "captcha", 119 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 120 require.Equal(t, appsec.CaptchaRemediation, responses[0].Action) 121 require.Equal(t, http.StatusForbidden, statusCode) 122 require.Equal(t, appsec.CaptchaRemediation, appsecResponse.Action) 123 require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus) 124 }, 125 }, 126 { 127 name: "no default remediation / custom user HTTP code", 128 expected_load_ok: true, 129 inband_rules: []appsec_rule.CustomRule{ 130 { 131 Name: "rule42", 132 Zones: []string{"ARGS"}, 133 Variables: []string{"foo"}, 134 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 135 Transform: []string{"lowercase"}, 136 }, 137 }, 138 input_request: appsec.ParsedRequest{ 139 RemoteAddr: "1.2.3.4", 140 Method: "GET", 141 URI: "/urllll", 142 Args: url.Values{"foo": []string{"toto"}}, 143 }, 144 UserBlockedHTTPCode: 418, 145 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 146 require.Equal(t, appsec.BanRemediation, responses[0].Action) 147 require.Equal(t, http.StatusForbidden, statusCode) 148 require.Equal(t, appsec.BanRemediation, appsecResponse.Action) 149 require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus) 150 }, 151 }, 152 { 153 name: "no match but try to set remediation to captcha with on_match hook", 154 expected_load_ok: true, 155 inband_rules: []appsec_rule.CustomRule{ 156 { 157 Name: "rule42", 158 Zones: []string{"ARGS"}, 159 Variables: []string{"foo"}, 160 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 161 Transform: []string{"lowercase"}, 162 }, 163 }, 164 on_match: []appsec.Hook{ 165 {Filter: "IsInBand == true", Apply: []string{"SetRemediation('captcha')"}}, 166 }, 167 input_request: appsec.ParsedRequest{ 168 RemoteAddr: "1.2.3.4", 169 Method: "GET", 170 URI: "/urllll", 171 Args: url.Values{"foo": []string{"bla"}}, 172 }, 173 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 174 require.Empty(t, events) 175 require.Equal(t, http.StatusOK, statusCode) 176 require.Equal(t, appsec.AllowRemediation, appsecResponse.Action) 177 }, 178 }, 179 { 180 name: "no match but try to set user HTTP code with on_match hook", 181 expected_load_ok: true, 182 inband_rules: []appsec_rule.CustomRule{ 183 { 184 Name: "rule42", 185 Zones: []string{"ARGS"}, 186 Variables: []string{"foo"}, 187 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 188 Transform: []string{"lowercase"}, 189 }, 190 }, 191 on_match: []appsec.Hook{ 192 {Filter: "IsInBand == true", Apply: []string{"SetReturnCode(418)"}}, 193 }, 194 input_request: appsec.ParsedRequest{ 195 RemoteAddr: "1.2.3.4", 196 Method: "GET", 197 URI: "/urllll", 198 Args: url.Values{"foo": []string{"bla"}}, 199 }, 200 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 201 require.Empty(t, events) 202 require.Equal(t, http.StatusOK, statusCode) 203 require.Equal(t, appsec.AllowRemediation, appsecResponse.Action) 204 }, 205 }, 206 { 207 name: "no match but try to set remediation with pre_eval hook", 208 expected_load_ok: true, 209 inband_rules: []appsec_rule.CustomRule{ 210 { 211 Name: "rule42", 212 Zones: []string{"ARGS"}, 213 Variables: []string{"foo"}, 214 Match: appsec_rule.Match{Type: "regex", Value: "^toto"}, 215 Transform: []string{"lowercase"}, 216 }, 217 }, 218 pre_eval: []appsec.Hook{ 219 {Filter: "IsInBand == true", Apply: []string{"SetRemediationByName('rule42', 'captcha')"}}, 220 }, 221 input_request: appsec.ParsedRequest{ 222 RemoteAddr: "1.2.3.4", 223 Method: "GET", 224 URI: "/urllll", 225 Args: url.Values{"foo": []string{"bla"}}, 226 }, 227 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 228 require.Empty(t, events) 229 require.Equal(t, http.StatusOK, statusCode) 230 require.Equal(t, appsec.AllowRemediation, appsecResponse.Action) 231 }, 232 }, 233 } 234 235 for _, test := range tests { 236 t.Run(test.name, func(t *testing.T) { 237 loadAppSecEngine(test, t) 238 }) 239 } 240 } 241 242 func TestAppsecRuleTransforms(t *testing.T) { 243 244 log.SetLevel(log.TraceLevel) 245 tests := []appsecRuleTest{ 246 { 247 name: "Basic matching rule", 248 expected_load_ok: true, 249 inband_rules: []appsec_rule.CustomRule{ 250 { 251 Name: "rule1", 252 Zones: []string{"URI"}, 253 Match: appsec_rule.Match{Type: "equals", Value: "/toto"}, 254 }, 255 }, 256 input_request: appsec.ParsedRequest{ 257 RemoteAddr: "1.2.3.4", 258 Method: "GET", 259 URI: "/toto", 260 }, 261 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 262 require.Len(t, events, 2) 263 require.Equal(t, types.APPSEC, events[0].Type) 264 require.Equal(t, types.LOG, events[1].Type) 265 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 266 }, 267 }, 268 { 269 name: "lowercase", 270 expected_load_ok: true, 271 inband_rules: []appsec_rule.CustomRule{ 272 { 273 Name: "rule1", 274 Zones: []string{"URI"}, 275 Match: appsec_rule.Match{Type: "equals", Value: "/toto"}, 276 Transform: []string{"lowercase"}, 277 }, 278 }, 279 input_request: appsec.ParsedRequest{ 280 RemoteAddr: "1.2.3.4", 281 Method: "GET", 282 URI: "/TOTO", 283 }, 284 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 285 require.Len(t, events, 2) 286 require.Equal(t, types.APPSEC, events[0].Type) 287 require.Equal(t, types.LOG, events[1].Type) 288 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 289 }, 290 }, 291 { 292 name: "uppercase", 293 expected_load_ok: true, 294 inband_rules: []appsec_rule.CustomRule{ 295 { 296 Name: "rule1", 297 Zones: []string{"URI"}, 298 Match: appsec_rule.Match{Type: "equals", Value: "/TOTO"}, 299 Transform: []string{"uppercase"}, 300 }, 301 }, 302 input_request: appsec.ParsedRequest{ 303 RemoteAddr: "1.2.3.4", 304 Method: "GET", 305 URI: "/toto", 306 }, 307 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 308 require.Len(t, events, 2) 309 require.Equal(t, types.APPSEC, events[0].Type) 310 require.Equal(t, types.LOG, events[1].Type) 311 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 312 }, 313 }, 314 { 315 name: "b64decode", 316 expected_load_ok: true, 317 inband_rules: []appsec_rule.CustomRule{ 318 { 319 Name: "rule1", 320 Zones: []string{"ARGS"}, 321 Variables: []string{"foo"}, 322 Match: appsec_rule.Match{Type: "equals", Value: "toto"}, 323 Transform: []string{"b64decode"}, 324 }, 325 }, 326 input_request: appsec.ParsedRequest{ 327 RemoteAddr: "1.2.3.4", 328 Method: "GET", 329 URI: "/?foo=dG90bw", 330 }, 331 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 332 require.Len(t, events, 2) 333 require.Equal(t, types.APPSEC, events[0].Type) 334 require.Equal(t, types.LOG, events[1].Type) 335 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 336 }, 337 }, 338 { 339 name: "b64decode with extra padding", 340 expected_load_ok: true, 341 inband_rules: []appsec_rule.CustomRule{ 342 { 343 Name: "rule1", 344 Zones: []string{"ARGS"}, 345 Variables: []string{"foo"}, 346 Match: appsec_rule.Match{Type: "equals", Value: "toto"}, 347 Transform: []string{"b64decode"}, 348 }, 349 }, 350 input_request: appsec.ParsedRequest{ 351 RemoteAddr: "1.2.3.4", 352 Method: "GET", 353 URI: "/?foo=dG90bw===", 354 }, 355 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 356 require.Len(t, events, 2) 357 require.Equal(t, types.APPSEC, events[0].Type) 358 require.Equal(t, types.LOG, events[1].Type) 359 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 360 }, 361 }, 362 { 363 name: "length", 364 expected_load_ok: true, 365 inband_rules: []appsec_rule.CustomRule{ 366 { 367 Name: "rule1", 368 Zones: []string{"ARGS"}, 369 Variables: []string{"foo"}, 370 Match: appsec_rule.Match{Type: "gte", Value: "3"}, 371 Transform: []string{"length"}, 372 }, 373 }, 374 input_request: appsec.ParsedRequest{ 375 RemoteAddr: "1.2.3.4", 376 Method: "GET", 377 URI: "/?foo=toto", 378 }, 379 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 380 require.Len(t, events, 2) 381 require.Equal(t, types.APPSEC, events[0].Type) 382 require.Equal(t, types.LOG, events[1].Type) 383 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 384 }, 385 }, 386 { 387 name: "urldecode", 388 expected_load_ok: true, 389 inband_rules: []appsec_rule.CustomRule{ 390 { 391 Name: "rule1", 392 Zones: []string{"ARGS"}, 393 Variables: []string{"foo"}, 394 Match: appsec_rule.Match{Type: "equals", Value: "BB/A"}, 395 Transform: []string{"urldecode"}, 396 }, 397 }, 398 input_request: appsec.ParsedRequest{ 399 RemoteAddr: "1.2.3.4", 400 Method: "GET", 401 URI: "/?foo=%42%42%2F%41", 402 }, 403 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 404 require.Len(t, events, 2) 405 require.Equal(t, types.APPSEC, events[0].Type) 406 require.Equal(t, types.LOG, events[1].Type) 407 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 408 }, 409 }, 410 { 411 name: "trim", 412 expected_load_ok: true, 413 inband_rules: []appsec_rule.CustomRule{ 414 { 415 Name: "rule1", 416 Zones: []string{"ARGS"}, 417 Variables: []string{"foo"}, 418 Match: appsec_rule.Match{Type: "equals", Value: "BB/A"}, 419 Transform: []string{"urldecode", "trim"}, 420 }, 421 }, 422 input_request: appsec.ParsedRequest{ 423 RemoteAddr: "1.2.3.4", 424 Method: "GET", 425 URI: "/?foo=%20%20%42%42%2F%41%20%20", 426 }, 427 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 428 require.Len(t, events, 2) 429 require.Equal(t, types.APPSEC, events[0].Type) 430 require.Equal(t, types.LOG, events[1].Type) 431 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 432 }, 433 }, 434 } 435 for _, test := range tests { 436 t.Run(test.name, func(t *testing.T) { 437 loadAppSecEngine(test, t) 438 }) 439 } 440 } 441 442 func TestAppsecRuleZones(t *testing.T) { 443 444 log.SetLevel(log.TraceLevel) 445 tests := []appsecRuleTest{ 446 { 447 name: "rule: ARGS", 448 expected_load_ok: true, 449 inband_rules: []appsec_rule.CustomRule{ 450 { 451 Name: "rule1", 452 Zones: []string{"ARGS"}, 453 Match: appsec_rule.Match{Type: "equals", Value: "toto"}, 454 }, 455 { 456 Name: "rule2", 457 Zones: []string{"ARGS"}, 458 Match: appsec_rule.Match{Type: "equals", Value: "foobar"}, 459 }, 460 }, 461 input_request: appsec.ParsedRequest{ 462 RemoteAddr: "1.2.3.4", 463 Method: "GET", 464 URI: "/foobar?something=toto&foobar=smth", 465 }, 466 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 467 require.Len(t, events, 2) 468 require.Equal(t, types.APPSEC, events[0].Type) 469 require.Equal(t, types.LOG, events[1].Type) 470 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 471 }, 472 }, 473 { 474 name: "rule: ARGS_NAMES", 475 expected_load_ok: true, 476 inband_rules: []appsec_rule.CustomRule{ 477 { 478 Name: "rule1", 479 Zones: []string{"ARGS_NAMES"}, 480 Match: appsec_rule.Match{Type: "equals", Value: "toto"}, 481 }, 482 { 483 Name: "rule2", 484 Zones: []string{"ARGS_NAMES"}, 485 Match: appsec_rule.Match{Type: "equals", Value: "foobar"}, 486 }, 487 }, 488 input_request: appsec.ParsedRequest{ 489 RemoteAddr: "1.2.3.4", 490 Method: "GET", 491 URI: "/foobar?something=toto&foobar=smth", 492 }, 493 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 494 require.Len(t, events, 2) 495 require.Equal(t, types.APPSEC, events[0].Type) 496 require.Equal(t, types.LOG, events[1].Type) 497 require.Equal(t, "rule2", events[1].Appsec.MatchedRules[0]["msg"]) 498 }, 499 }, 500 { 501 name: "rule: BODY_ARGS", 502 expected_load_ok: true, 503 inband_rules: []appsec_rule.CustomRule{ 504 { 505 Name: "rule1", 506 Zones: []string{"BODY_ARGS"}, 507 Match: appsec_rule.Match{Type: "equals", Value: "toto"}, 508 }, 509 { 510 Name: "rule2", 511 Zones: []string{"BODY_ARGS"}, 512 Match: appsec_rule.Match{Type: "equals", Value: "foobar"}, 513 }, 514 }, 515 input_request: appsec.ParsedRequest{ 516 RemoteAddr: "1.2.3.4", 517 Method: "GET", 518 URI: "/", 519 Body: []byte("smth=toto&foobar=other"), 520 Headers: http.Header{"Content-Type": []string{"application/x-www-form-urlencoded"}}, 521 }, 522 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 523 require.Len(t, events, 2) 524 require.Equal(t, types.APPSEC, events[0].Type) 525 require.Equal(t, types.LOG, events[1].Type) 526 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 527 }, 528 }, 529 { 530 name: "rule: BODY_ARGS_NAMES", 531 expected_load_ok: true, 532 inband_rules: []appsec_rule.CustomRule{ 533 { 534 Name: "rule1", 535 Zones: []string{"BODY_ARGS_NAMES"}, 536 Match: appsec_rule.Match{Type: "equals", Value: "toto"}, 537 }, 538 { 539 Name: "rule2", 540 Zones: []string{"BODY_ARGS_NAMES"}, 541 Match: appsec_rule.Match{Type: "equals", Value: "foobar"}, 542 }, 543 }, 544 input_request: appsec.ParsedRequest{ 545 RemoteAddr: "1.2.3.4", 546 Method: "GET", 547 URI: "/", 548 Body: []byte("smth=toto&foobar=other"), 549 Headers: http.Header{"Content-Type": []string{"application/x-www-form-urlencoded"}}, 550 }, 551 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 552 require.Len(t, events, 2) 553 require.Equal(t, types.APPSEC, events[0].Type) 554 require.Equal(t, types.LOG, events[1].Type) 555 require.Equal(t, "rule2", events[1].Appsec.MatchedRules[0]["msg"]) 556 }, 557 }, 558 { 559 name: "rule: HEADERS", 560 expected_load_ok: true, 561 inband_rules: []appsec_rule.CustomRule{ 562 { 563 Name: "rule1", 564 Zones: []string{"HEADERS"}, 565 Match: appsec_rule.Match{Type: "equals", Value: "toto"}, 566 }, 567 { 568 Name: "rule2", 569 Zones: []string{"HEADERS"}, 570 Match: appsec_rule.Match{Type: "equals", Value: "foobar"}, 571 }, 572 }, 573 input_request: appsec.ParsedRequest{ 574 RemoteAddr: "1.2.3.4", 575 Method: "GET", 576 URI: "/", 577 Headers: http.Header{"foobar": []string{"toto"}}, 578 }, 579 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 580 require.Len(t, events, 2) 581 require.Equal(t, types.APPSEC, events[0].Type) 582 require.Equal(t, types.LOG, events[1].Type) 583 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 584 }, 585 }, 586 { 587 name: "rule: HEADERS_NAMES", 588 expected_load_ok: true, 589 inband_rules: []appsec_rule.CustomRule{ 590 { 591 Name: "rule1", 592 Zones: []string{"HEADERS_NAMES"}, 593 Match: appsec_rule.Match{Type: "equals", Value: "toto"}, 594 }, 595 { 596 Name: "rule2", 597 Zones: []string{"HEADERS_NAMES"}, 598 Match: appsec_rule.Match{Type: "equals", Value: "foobar"}, 599 }, 600 }, 601 input_request: appsec.ParsedRequest{ 602 RemoteAddr: "1.2.3.4", 603 Method: "GET", 604 URI: "/", 605 Headers: http.Header{"foobar": []string{"toto"}}, 606 }, 607 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 608 require.Len(t, events, 2) 609 require.Equal(t, types.APPSEC, events[0].Type) 610 require.Equal(t, types.LOG, events[1].Type) 611 require.Equal(t, "rule2", events[1].Appsec.MatchedRules[0]["msg"]) 612 }, 613 }, 614 { 615 name: "rule: METHOD", 616 expected_load_ok: true, 617 inband_rules: []appsec_rule.CustomRule{ 618 { 619 Name: "rule1", 620 Zones: []string{"METHOD"}, 621 Match: appsec_rule.Match{Type: "equals", Value: "GET"}, 622 }, 623 }, 624 input_request: appsec.ParsedRequest{ 625 RemoteAddr: "1.2.3.4", 626 Method: "GET", 627 URI: "/", 628 }, 629 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 630 require.Len(t, events, 2) 631 require.Equal(t, types.APPSEC, events[0].Type) 632 require.Equal(t, types.LOG, events[1].Type) 633 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 634 }, 635 }, 636 { 637 name: "rule: PROTOCOL", 638 expected_load_ok: true, 639 inband_rules: []appsec_rule.CustomRule{ 640 { 641 Name: "rule1", 642 Zones: []string{"PROTOCOL"}, 643 Match: appsec_rule.Match{Type: "contains", Value: "3.1"}, 644 }, 645 }, 646 input_request: appsec.ParsedRequest{ 647 RemoteAddr: "1.2.3.4", 648 Method: "GET", 649 URI: "/", 650 Proto: "HTTP/3.1", 651 }, 652 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 653 require.Len(t, events, 2) 654 require.Equal(t, types.APPSEC, events[0].Type) 655 require.Equal(t, types.LOG, events[1].Type) 656 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 657 }, 658 }, 659 { 660 name: "rule: URI", 661 expected_load_ok: true, 662 inband_rules: []appsec_rule.CustomRule{ 663 { 664 Name: "rule1", 665 Zones: []string{"URI"}, 666 Match: appsec_rule.Match{Type: "equals", Value: "/foobar"}, 667 }, 668 }, 669 input_request: appsec.ParsedRequest{ 670 RemoteAddr: "1.2.3.4", 671 Method: "GET", 672 URI: "/foobar", 673 }, 674 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 675 require.Len(t, events, 2) 676 require.Equal(t, types.APPSEC, events[0].Type) 677 require.Equal(t, types.LOG, events[1].Type) 678 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 679 }, 680 }, 681 { 682 name: "rule: URI_FULL", 683 expected_load_ok: true, 684 inband_rules: []appsec_rule.CustomRule{ 685 { 686 Name: "rule1", 687 Zones: []string{"URI_FULL"}, 688 Match: appsec_rule.Match{Type: "equals", Value: "/foobar?a=b"}, 689 }, 690 }, 691 input_request: appsec.ParsedRequest{ 692 RemoteAddr: "1.2.3.4", 693 Method: "GET", 694 URI: "/foobar?a=b", 695 }, 696 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 697 require.Len(t, events, 2) 698 require.Equal(t, types.APPSEC, events[0].Type) 699 require.Equal(t, types.LOG, events[1].Type) 700 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 701 }, 702 }, 703 { 704 name: "rule: RAW_BODY", 705 expected_load_ok: true, 706 inband_rules: []appsec_rule.CustomRule{ 707 { 708 Name: "rule1", 709 Zones: []string{"RAW_BODY"}, 710 Match: appsec_rule.Match{Type: "equals", Value: "foobar=42421"}, 711 }, 712 }, 713 input_request: appsec.ParsedRequest{ 714 RemoteAddr: "1.2.3.4", 715 Method: "GET", 716 URI: "/", 717 Body: []byte("foobar=42421"), 718 Headers: http.Header{"Content-Type": []string{"application/x-www-form-urlencoded"}}, 719 }, 720 output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { 721 require.Len(t, events, 2) 722 require.Equal(t, types.APPSEC, events[0].Type) 723 require.Equal(t, types.LOG, events[1].Type) 724 require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"]) 725 }, 726 }, 727 } 728 for _, test := range tests { 729 t.Run(test.name, func(t *testing.T) { 730 loadAppSecEngine(test, t) 731 }) 732 } 733 }