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  }