Skip to content

Commit

Permalink
appsec: respect on_success parameter in hooks (#3017)
Browse files Browse the repository at this point in the history
  • Loading branch information
blotus authored May 24, 2024
1 parent 45b403e commit 09afcbe
Show file tree
Hide file tree
Showing 2 changed files with 221 additions and 11 deletions.
198 changes: 189 additions & 9 deletions pkg/acquisition/modules/appsec/appsec_hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,64 @@ func TestAppsecOnMatchHooks(t *testing.T) {
require.Equal(t, appsec.BanRemediation, responses[0].Action)
},
},
{
name: "on_match: on_success break",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Name: "rule42",
Zones: []string{"ARGS"},
Variables: []string{"foo"},
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
Transform: []string{"lowercase"},
},
},
on_match: []appsec.Hook{
{Filter: "IsInBand == true", Apply: []string{"CancelEvent()"}, OnSuccess: "break"},
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('captcha')"}},
},
input_request: appsec.ParsedRequest{
RemoteAddr: "1.2.3.4",
Method: "GET",
URI: "/urllll",
Args: url.Values{"foo": []string{"toto"}},
},
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
require.Len(t, events, 1)
require.Equal(t, types.APPSEC, events[0].Type)
require.Len(t, responses, 1)
require.Equal(t, appsec.BanRemediation, responses[0].Action)
},
},
{
name: "on_match: on_success continue",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Name: "rule42",
Zones: []string{"ARGS"},
Variables: []string{"foo"},
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
Transform: []string{"lowercase"},
},
},
on_match: []appsec.Hook{
{Filter: "IsInBand == true", Apply: []string{"CancelEvent()"}, OnSuccess: "continue"},
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('captcha')"}},
},
input_request: appsec.ParsedRequest{
RemoteAddr: "1.2.3.4",
Method: "GET",
URI: "/urllll",
Args: url.Values{"foo": []string{"toto"}},
},
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
require.Len(t, events, 1)
require.Equal(t, types.APPSEC, events[0].Type)
require.Len(t, responses, 1)
require.Equal(t, appsec.CaptchaRemediation, responses[0].Action)
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
Expand All @@ -286,7 +344,7 @@ func TestAppsecPreEvalHooks(t *testing.T) {

tests := []appsecRuleTest{
{
name: "Basic on_load hook to disable inband rule",
name: "Basic pre_eval hook to disable inband rule",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Expand Down Expand Up @@ -314,7 +372,7 @@ func TestAppsecPreEvalHooks(t *testing.T) {
},
},
{
name: "Basic on_load fails to disable rule",
name: "Basic pre_eval fails to disable rule",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Expand Down Expand Up @@ -349,7 +407,7 @@ func TestAppsecPreEvalHooks(t *testing.T) {
},
},
{
name: "on_load : disable inband by tag",
name: "pre_eval : disable inband by tag",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Expand Down Expand Up @@ -377,7 +435,7 @@ func TestAppsecPreEvalHooks(t *testing.T) {
},
},
{
name: "on_load : disable inband by ID",
name: "pre_eval : disable inband by ID",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Expand Down Expand Up @@ -405,7 +463,7 @@ func TestAppsecPreEvalHooks(t *testing.T) {
},
},
{
name: "on_load : disable inband by name",
name: "pre_eval : disable inband by name",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Expand Down Expand Up @@ -433,7 +491,7 @@ func TestAppsecPreEvalHooks(t *testing.T) {
},
},
{
name: "on_load : outofband default behavior",
name: "pre_eval : outofband default behavior",
expected_load_ok: true,
outofband_rules: []appsec_rule.CustomRule{
{
Expand Down Expand Up @@ -464,7 +522,7 @@ func TestAppsecPreEvalHooks(t *testing.T) {
},
},
{
name: "on_load : set remediation by tag",
name: "pre_eval : set remediation by tag",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Expand All @@ -491,7 +549,7 @@ func TestAppsecPreEvalHooks(t *testing.T) {
},
},
{
name: "on_load : set remediation by name",
name: "pre_eval : set remediation by name",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Expand All @@ -518,7 +576,7 @@ func TestAppsecPreEvalHooks(t *testing.T) {
},
},
{
name: "on_load : set remediation by ID",
name: "pre_eval : set remediation by ID",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Expand Down Expand Up @@ -546,6 +604,62 @@ func TestAppsecPreEvalHooks(t *testing.T) {
require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus)
},
},
{
name: "pre_eval : on_success continue",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Name: "rulez",
Zones: []string{"ARGS"},
Variables: []string{"foo"},
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
Transform: []string{"lowercase"},
},
},
pre_eval: []appsec.Hook{
{Filter: "1==1", Apply: []string{"SetRemediationByName('rulez', 'foobar')"}, OnSuccess: "continue"},
{Filter: "1==1", Apply: []string{"SetRemediationByName('rulez', 'foobar2')"}},
},
input_request: appsec.ParsedRequest{
RemoteAddr: "1.2.3.4",
Method: "GET",
URI: "/urllll",
Args: url.Values{"foo": []string{"toto"}},
},
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
require.Len(t, events, 2)
require.Len(t, responses, 1)
require.Equal(t, "foobar2", responses[0].Action)
},
},
{
name: "pre_eval : on_success break",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Name: "rulez",
Zones: []string{"ARGS"},
Variables: []string{"foo"},
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
Transform: []string{"lowercase"},
},
},
pre_eval: []appsec.Hook{
{Filter: "1==1", Apply: []string{"SetRemediationByName('rulez', 'foobar')"}, OnSuccess: "break"},
{Filter: "1==1", Apply: []string{"SetRemediationByName('rulez', 'foobar2')"}},
},
input_request: appsec.ParsedRequest{
RemoteAddr: "1.2.3.4",
Method: "GET",
URI: "/urllll",
Args: url.Values{"foo": []string{"toto"}},
},
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
require.Len(t, events, 2)
require.Len(t, responses, 1)
require.Equal(t, "foobar", responses[0].Action)
},
},
}

for _, test := range tests {
Expand Down Expand Up @@ -705,6 +819,72 @@ func TestOnMatchRemediationHooks(t *testing.T) {
require.Equal(t, http.StatusForbidden, statusCode)
},
},
{
name: "on_match: on_success break",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Name: "rule42",
Zones: []string{"ARGS"},
Variables: []string{"foo"},
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
Transform: []string{"lowercase"},
},
},
input_request: appsec.ParsedRequest{
RemoteAddr: "1.2.3.4",
Method: "GET",
URI: "/urllll",
Args: url.Values{"foo": []string{"toto"}},
},
DefaultRemediation: appsec.AllowRemediation,
on_match: []appsec.Hook{
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('captcha')", "SetReturnCode(418)"}, OnSuccess: "break"},
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('ban')"}},
},
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
spew.Dump(responses)
spew.Dump(appsecResponse)

log.Errorf("http status : %d", statusCode)
require.Equal(t, appsec.CaptchaRemediation, appsecResponse.Action)
require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus)
require.Equal(t, http.StatusForbidden, statusCode)
},
},
{
name: "on_match: on_success continue",
expected_load_ok: true,
inband_rules: []appsec_rule.CustomRule{
{
Name: "rule42",
Zones: []string{"ARGS"},
Variables: []string{"foo"},
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
Transform: []string{"lowercase"},
},
},
input_request: appsec.ParsedRequest{
RemoteAddr: "1.2.3.4",
Method: "GET",
URI: "/urllll",
Args: url.Values{"foo": []string{"toto"}},
},
DefaultRemediation: appsec.AllowRemediation,
on_match: []appsec.Hook{
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('captcha')", "SetReturnCode(418)"}, OnSuccess: "continue"},
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('ban')"}},
},
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
spew.Dump(responses)
spew.Dump(appsecResponse)

log.Errorf("http status : %d", statusCode)
require.Equal(t, appsec.BanRemediation, appsecResponse.Action)
require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus)
require.Equal(t, http.StatusForbidden, statusCode)
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
Expand Down
Loading

0 comments on commit 09afcbe

Please sign in to comment.