diff --git a/pkg/acquisition/modules/appsec/appsec_hooks_test.go b/pkg/acquisition/modules/appsec/appsec_hooks_test.go index c549d2ef1..3a8ac57f3 100644 --- a/pkg/acquisition/modules/appsec/appsec_hooks_test.go +++ b/pkg/acquisition/modules/appsec/appsec_hooks_test.go @@ -660,6 +660,34 @@ func TestAppsecPreEvalHooks(t *testing.T) { require.Equal(t, "foobar", responses[0].Action) }, }, + { + name: "pre_eval : SetRemediation (WAF rule in expr) + Bypass", + 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: "IsInBand && 1 == 1", Apply: []string{"SetRemediation('ban')", "SetReturnCode(403)"}}, + }, + input_request: appsec.ParsedRequest{ + RemoteAddr: "1.2.3.4", + Method: "GET", + URI: "/urllll", + Args: url.Values{"bar": []string{"bar"}}, + }, + output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) { + require.Equal(t, appsec.BanRemediation, responses[0].Action) + //require.Equal(t, http.StatusForbidden, statusCode) + require.Equal(t, appsec.BanRemediation, appsecResponse.Action) + //require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus) + }, + }, } for _, test := range tests { diff --git a/pkg/acquisition/modules/appsec/appsec_runner.go b/pkg/acquisition/modules/appsec/appsec_runner.go index ed49d6a7b..7245ac3bd 100644 --- a/pkg/acquisition/modules/appsec/appsec_runner.go +++ b/pkg/acquisition/modules/appsec/appsec_runner.go @@ -128,6 +128,10 @@ func (r *AppsecRunner) processRequest(tx appsec.ExtendedTransaction, request *ap } }() + r.logger.Infof("(before pre_eval) planned remediation: %s", r.AppsecRuntime.Response.Action) //.Response.Action = + r.logger.Infof("(before pre_eval) planned resp code: %d", r.AppsecRuntime.Response.UserHTTPResponseCode) //.Response.Action = + r.logger.Infof("(before pre_eval) planned response: %+v", r.AppsecRuntime.Response) //.Response.Action = + //pre eval (expr) rules err = r.AppsecRuntime.ProcessPreEvalRules(request) if err != nil { @@ -135,6 +139,14 @@ func (r *AppsecRunner) processRequest(tx appsec.ExtendedTransaction, request *ap //FIXME: should we abort here ? } + r.logger.Infof("(after pre_eval) planned remediation: %s", r.AppsecRuntime.Response.Action) //.Response.Action = + r.logger.Infof("(after pre_eval) planned resp code: %d", r.AppsecRuntime.Response.UserHTTPResponseCode) //.Response.Action = + r.logger.Infof("(after pre_eval) planned response: %+v", r.AppsecRuntime.Response) //.Response.Action = + + if r.AppsecRuntime.FlagSkipProcessing { + return nil + } + request.Tx.ProcessConnection(request.RemoteAddr, 0, "", 0) for k, v := range request.Args { @@ -214,6 +226,8 @@ func (r *AppsecRunner) ProcessOutOfBandRules(request *appsec.ParsedRequest) erro } func (r *AppsecRunner) handleInBandInterrupt(request *appsec.ParsedRequest) { + + r.logger.Infof("entering inband interrupt") //create the associated event for crowdsec itself evt, err := EventFromRequest(request, r.Labels) if err != nil { @@ -322,6 +336,9 @@ func (r *AppsecRunner) handleRequest(request *appsec.ParsedRequest) { logger.Errorf("unable to process InBand rules: %s", err) return } + logger.Infof("(after processInBand) planned remediation: %s", r.AppsecRuntime.Response.Action) //.Response.Action = + logger.Infof("(after processInBand) planned resp code: %d", r.AppsecRuntime.Response.UserHTTPResponseCode) //.Response.Action = + logger.Infof("(after processInBand) planned response: %+v", r.AppsecRuntime.Response) //.Response.Action = // time spent to process in band rules inBandParsingElapsed := time.Since(startInBandParsing) diff --git a/pkg/appsec/appsec.go b/pkg/appsec/appsec.go index 96f977b47..3b20fc07d 100644 --- a/pkg/appsec/appsec.go +++ b/pkg/appsec/appsec.go @@ -87,7 +87,8 @@ type AppsecSubEngineOpts struct { // runtime version of AppsecConfig type AppsecRuntimeConfig struct { - Name string + Name string + OutOfBandRules []AppsecCollection InBandRules []AppsecCollection @@ -107,6 +108,8 @@ type AppsecRuntimeConfig struct { OutOfBandTx ExtendedTransaction //is it a good idea ? InBandTx ExtendedTransaction //is it a good idea ? Response AppsecTempResponse + + FlagSkipProcessing bool //should we store matched rules here ? Logger *log.Entry @@ -603,6 +606,15 @@ func (w *AppsecRuntimeConfig) SetActionByName(name string, action string) error return nil } +func (w *AppsecRuntimeConfig) DenyRequest() error { + w.Logger.Debugf("setting action to deny") + w.Response.Action = BanRemediation + w.Response.BouncerHTTPResponseCode = w.Config.BouncerBlockedHTTPCode + w.Response.UserHTTPResponseCode = w.Config.UserBlockedHTTPCode + //w.Response.InBandInterrupt = true + return nil +} + func (w *AppsecRuntimeConfig) SetAction(action string) error { //log.Infof("setting to %s", action) w.Logger.Debugf("setting action to %s", action) @@ -616,6 +628,12 @@ func (w *AppsecRuntimeConfig) SetHTTPCode(code int) error { return nil } +func (w *AppsecRuntimeConfig) SkipProcessing() error { + w.Logger.Debugf("setting flag to skip normal processing") + w.FlagSkipProcessing = true + return nil +} + type BodyResponse struct { Action string `json:"action"` HTTPStatus int `json:"http_status"` diff --git a/pkg/appsec/waf_helpers.go b/pkg/appsec/waf_helpers.go index 3d9a96a0d..8a03e889e 100644 --- a/pkg/appsec/waf_helpers.go +++ b/pkg/appsec/waf_helpers.go @@ -32,6 +32,10 @@ func GetPreEvalEnv(w *AppsecRuntimeConfig, request *ParsedRequest) map[string]in "SetRemediationByTag": w.SetActionByTag, "SetRemediationByID": w.SetActionByID, "SetRemediationByName": w.SetActionByName, + "SetRemediation": w.SetAction, + "SetReturnCode": w.SetHTTPCode, + "SkipProcessing": w.SkipProcessing, + "DenyRequest": w.DenyRequest, } }