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  }