up wip
This commit is contained in:
parent
c435447d8e
commit
2e60e8021c
6 changed files with 144 additions and 77 deletions
|
@ -52,6 +52,11 @@ type WaapSource struct {
|
|||
WaapRunners []WaapRunner //one for each go-routine
|
||||
}
|
||||
|
||||
// @tko + @sbl : we might want to get rid of that or improve it
|
||||
type BodyResponse struct {
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
func (wc *WaapSource) UnmarshalConfig(yamlConfig []byte) error {
|
||||
|
||||
err := yaml.UnmarshalStrict(yamlConfig, &wc.config)
|
||||
|
@ -165,10 +170,13 @@ func (w *WaapSource) Configure(yamlConfig []byte, logger *log.Entry) error {
|
|||
})
|
||||
}
|
||||
|
||||
//we copy WaapRutime for each runner
|
||||
wrt := *w.WaapRuntime
|
||||
runner := WaapRunner{
|
||||
inChan: w.InChan,
|
||||
UUID: wafUUID,
|
||||
logger: wafLogger,
|
||||
inChan: w.InChan,
|
||||
UUID: wafUUID,
|
||||
logger: wafLogger,
|
||||
WaapRuntime: &wrt,
|
||||
}
|
||||
w.WaapRunners[nbRoutine] = runner
|
||||
//most likely missign somethign here to actually start the runner :)
|
||||
|
@ -247,10 +255,6 @@ func (w *WaapSource) Dump() interface{} {
|
|||
return w
|
||||
}
|
||||
|
||||
type BodyResponse struct {
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
// should this be in the runner ?
|
||||
func (w *WaapSource) waapHandler(rw http.ResponseWriter, r *http.Request) {
|
||||
// parse the request only once
|
||||
|
@ -264,6 +268,7 @@ func (w *WaapSource) waapHandler(rw http.ResponseWriter, r *http.Request) {
|
|||
|
||||
message := <-parsedRequest.ResponseChannel
|
||||
|
||||
//@tko this parts needs to be redone
|
||||
if message.Err != nil {
|
||||
log.Errorf("Error while processing InBAND: %s", err)
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
|
|
|
@ -31,10 +31,10 @@ func (r *WaapRunner) Run(t *tomb.Tomb) error {
|
|||
return nil
|
||||
case request := <-r.inChan:
|
||||
r.logger.Infof("Requests handled by runner %s", request.UUID)
|
||||
r.WaapRuntime.ClearResponse()
|
||||
|
||||
//tx := waf.NewExtendedTransaction(r.WaapInbandEngine, r.UUID)
|
||||
WafReqCounter.With(prometheus.Labels{"source": request.RemoteAddr}).Inc()
|
||||
//measure the time spent in the WAF
|
||||
//to measure the time spent in the WAF
|
||||
startParsing := time.Now()
|
||||
|
||||
//pre eval (expr) rules
|
||||
|
@ -43,7 +43,6 @@ func (r *WaapRunner) Run(t *tomb.Tomb) error {
|
|||
r.logger.Errorf("unable to process PreEval rules: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
//inband WAAP rules
|
||||
interrupt, err := r.WaapRuntime.ProcessInBandRules(request)
|
||||
elapsed := time.Since(startParsing)
|
||||
|
|
|
@ -25,18 +25,17 @@ func (t *ExtendedTransaction) RemoveRuleByIDWithError(id int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func GetEnv() map[string]interface{} {
|
||||
ResponseRequest := ResponseRequest{}
|
||||
ParsedRequest := ParsedRequest{}
|
||||
Rules := &WaapCollection{}
|
||||
Tx := ExtendedTransaction{}
|
||||
|
||||
// simply used to ease the compilation & runtime of the hooks
|
||||
func GetHookEnv(w WaapRuntimeConfig, request ParsedRequest) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"rules": Rules,
|
||||
"req": ParsedRequest,
|
||||
"SetRemediation": ResponseRequest.SetRemediation,
|
||||
"SetRemediationByID": ResponseRequest.SetRemediationByID,
|
||||
"CancelEvent": ResponseRequest.CancelEvent,
|
||||
"RemoveRuleByID": Tx.RemoveRuleByIDWithError,
|
||||
"inband_rules": w.InBandRules,
|
||||
"outband_rules": w.OutOfBandRules,
|
||||
"req": request,
|
||||
"RemoveInbandRuleByID": w.RemoveInbandRuleByID,
|
||||
"RemoveOutbandRuleByID": w.RemoveOutbandRuleByID,
|
||||
"SetAction": w.SetAction,
|
||||
"SetHTTPCode": w.SetHTTPCode,
|
||||
"SetActionByID": w.SetActionnByID,
|
||||
"CancelEvent": w.CancelEvent,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,29 +36,29 @@ func NewResponseRequest(Tx experimental.FullTransaction, in *corazatypes.Interru
|
|||
}
|
||||
}
|
||||
|
||||
func (r *ResponseRequest) SetRemediation(remediation string) error {
|
||||
if r.Interruption == nil {
|
||||
return nil
|
||||
}
|
||||
r.Interruption.Action = remediation
|
||||
return nil
|
||||
}
|
||||
// func (r *ResponseRequest) SetRemediation(remediation string) error {
|
||||
// if r.Interruption == nil {
|
||||
// return nil
|
||||
// }
|
||||
// r.Interruption.Action = remediation
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func (r *ResponseRequest) SetRemediationByID(ID int, remediation string) error {
|
||||
if r.Interruption == nil {
|
||||
return nil
|
||||
}
|
||||
if r.Interruption.RuleID == ID {
|
||||
r.Interruption.Action = remediation
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// func (r *ResponseRequest) SetRemediationByID(ID int, remediation string) error {
|
||||
// if r.Interruption == nil {
|
||||
// return nil
|
||||
// }
|
||||
// if r.Interruption.RuleID == ID {
|
||||
// r.Interruption.Action = remediation
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func (r *ResponseRequest) CancelEvent() error {
|
||||
// true by default
|
||||
r.SendEvents = false
|
||||
return nil
|
||||
}
|
||||
// func (r *ResponseRequest) CancelEvent() error {
|
||||
// // true by default
|
||||
// r.SendEvents = false
|
||||
// return nil
|
||||
// }
|
||||
|
||||
type ParsedRequest struct {
|
||||
RemoteAddr string
|
||||
|
@ -77,6 +77,7 @@ type ParsedRequest struct {
|
|||
ResponseChannel chan ResponseRequest
|
||||
}
|
||||
|
||||
// Generate a ParsedRequest from a http.Request. ParsedRequest can be consumed by the Waap Engine
|
||||
func NewParsedRequestFromRequest(r *http.Request) (ParsedRequest, error) {
|
||||
var err error
|
||||
body := make([]byte, 0)
|
||||
|
|
122
pkg/waf/waap.go
122
pkg/waf/waap.go
|
@ -21,6 +21,7 @@ type Hook struct {
|
|||
ApplyExpr []*vm.Program `yaml:"-"`
|
||||
}
|
||||
|
||||
// @tko : todo - debug mode
|
||||
func (h *Hook) Build() error {
|
||||
|
||||
if h.Filter != "" {
|
||||
|
@ -31,7 +32,7 @@ func (h *Hook) Build() error {
|
|||
h.FilterExpr = program
|
||||
}
|
||||
for _, apply := range h.Apply {
|
||||
program, err := expr.Compile(apply, GetExprWAFOptions(GetEnv())...)
|
||||
program, err := expr.Compile(apply, GetExprWAFOptions(GetHookEnv(WaapRuntimeConfig{}, ParsedRequest{}))...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to compile apply %s : %w", apply, err)
|
||||
}
|
||||
|
@ -40,18 +41,30 @@ func (h *Hook) Build() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type WaapTempResponse struct {
|
||||
InBandInterrupt bool
|
||||
OutOfBandInterrupt bool
|
||||
Action string //allow, deny, captcha, log
|
||||
HTTPResponseCode int
|
||||
SendEvent bool //do we send an internal event on rule match
|
||||
}
|
||||
|
||||
// runtime version of WaapConfig
|
||||
type WaapRuntimeConfig struct {
|
||||
Name string
|
||||
OutOfBandRules []WaapCollection
|
||||
OutOfBandTx ExtendedTransaction //is it a good idea ?
|
||||
InBandRules []WaapCollection
|
||||
InBandTx ExtendedTransaction //is it a good idea ?
|
||||
DefaultRemediation string
|
||||
CompiledOnLoad []Hook
|
||||
CompiledPreEval []Hook
|
||||
CompiledOnMatch []Hook
|
||||
CompiledVariablesTracking []*regexp.Regexp
|
||||
Config *WaapConfig
|
||||
|
||||
//those are ephemeral, created/destroyed with every req
|
||||
OutOfBandTx ExtendedTransaction //is it a good idea ?
|
||||
InBandTx ExtendedTransaction //is it a good idea ?
|
||||
Response WaapTempResponse
|
||||
}
|
||||
|
||||
type WaapConfig struct {
|
||||
|
@ -59,12 +72,24 @@ type WaapConfig struct {
|
|||
OutOfBandRules []string `yaml:"outofband_rules"`
|
||||
InBandRules []string `yaml:"inband_rules"`
|
||||
DefaultRemediation string `yaml:"default_remediation"`
|
||||
DefaultPassAction string `yaml:"default_pass_action"`
|
||||
BlockedHTTPCode int `yaml:"blocked_http_code"`
|
||||
PassedHTTPCode int `yaml:"passed_http_code"`
|
||||
OnLoad []Hook `yaml:"on_load"`
|
||||
PreEval []Hook `yaml:"pre_eval"`
|
||||
OnMatch []Hook `yaml:"on_match"`
|
||||
VariablesTracking []string `yaml:"variables_tracking"`
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) ClearResponse() {
|
||||
log.Infof("#-> %p", w)
|
||||
w.Response = WaapTempResponse{}
|
||||
log.Infof("-> %p", w.Config)
|
||||
w.Response.Action = w.Config.DefaultPassAction
|
||||
w.Response.HTTPResponseCode = w.Config.PassedHTTPCode
|
||||
w.Response.SendEvent = true
|
||||
}
|
||||
|
||||
func (wc *WaapConfig) Load(file string) error {
|
||||
yamlFile, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
|
@ -74,6 +99,21 @@ func (wc *WaapConfig) Load(file string) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("unable to parse yaml file %s : %s", file, err)
|
||||
}
|
||||
if wc.Name == "" {
|
||||
return fmt.Errorf("name cannot be empty")
|
||||
}
|
||||
if wc.DefaultRemediation == "" {
|
||||
return fmt.Errorf("default_remediation cannot be empty")
|
||||
}
|
||||
if wc.BlockedHTTPCode == 0 {
|
||||
wc.BlockedHTTPCode = 403
|
||||
}
|
||||
if wc.PassedHTTPCode == 0 {
|
||||
wc.PassedHTTPCode = 200
|
||||
}
|
||||
if wc.DefaultPassAction == "" {
|
||||
wc.DefaultPassAction = "allow"
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
@ -81,6 +121,7 @@ func (wc *WaapConfig) Load(file string) error {
|
|||
func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) {
|
||||
ret := &WaapRuntimeConfig{}
|
||||
ret.Name = wc.Name
|
||||
ret.Config = wc
|
||||
ret.DefaultRemediation = wc.DefaultRemediation
|
||||
|
||||
//load rules
|
||||
|
@ -160,13 +201,12 @@ func (w *WaapRuntimeConfig) ProcessOnMatchRules(request ParsedRequest, response
|
|||
}
|
||||
for _, applyExpr := range rule.ApplyExpr {
|
||||
_, err := expr.Run(applyExpr, map[string]interface{}{
|
||||
//"rules": w.InBandTx.Tx.Rules, //what is it supposed to be ? matched rules ?
|
||||
"req": request,
|
||||
"RemoveInbandRuleByID": w.RemoveInbandRuleByID,
|
||||
"RemoveOutbandRuleByID": w.RemoveOutbandRuleByID,
|
||||
"SetRemediation": response.SetRemediation,
|
||||
"SetRemediationByID": response.SetRemediationByID,
|
||||
"CancelEvent": response.CancelEvent,
|
||||
// "req": request,
|
||||
// "RemoveInbandRuleByID": w.RemoveInbandRuleByID,
|
||||
// "RemoveOutbandRuleByID": w.RemoveOutbandRuleByID,
|
||||
// "SetAction": response.SetAction,
|
||||
// "SetRemediationByID": response.SetRemediationByID,
|
||||
// "CancelEvent": response.CancelEvent,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("unable to apply filter: %s", err)
|
||||
|
@ -180,10 +220,7 @@ func (w *WaapRuntimeConfig) ProcessOnMatchRules(request ParsedRequest, response
|
|||
func (w *WaapRuntimeConfig) ProcessPreEvalRules(request ParsedRequest) error {
|
||||
for _, rule := range w.CompiledPreEval {
|
||||
if rule.FilterExpr != nil {
|
||||
output, err := expr.Run(rule.FilterExpr, map[string]interface{}{
|
||||
//"rules": rules, //is it still useful ?
|
||||
"req": request,
|
||||
})
|
||||
output, err := expr.Run(rule.FilterExpr, GetHookEnv(*w, request))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to run filter %s : %w", rule.Filter, err)
|
||||
}
|
||||
|
@ -200,13 +237,7 @@ func (w *WaapRuntimeConfig) ProcessPreEvalRules(request ParsedRequest) error {
|
|||
}
|
||||
// here means there is no filter or the filter matched
|
||||
for _, applyExpr := range rule.ApplyExpr {
|
||||
_, err := expr.Run(applyExpr, map[string]interface{}{
|
||||
"inband_rules": w.InBandRules,
|
||||
"outband_rules": w.OutOfBandRules,
|
||||
"req": request,
|
||||
"RemoveInbandRuleByID": w.RemoveInbandRuleByID,
|
||||
"RemoveOutbandRuleByID": w.RemoveOutbandRuleByID,
|
||||
})
|
||||
_, err := expr.Run(applyExpr, GetHookEnv(*w, request))
|
||||
if err != nil {
|
||||
log.Errorf("unable to apply filter: %s", err)
|
||||
continue
|
||||
|
@ -221,15 +252,37 @@ func (w *WaapRuntimeConfig) ProcessPreEvalRules(request ParsedRequest) error {
|
|||
add the helpers to:
|
||||
- remove by id-range
|
||||
- remove by tag
|
||||
- set remediation by tag/id-range
|
||||
|
||||
*/
|
||||
|
||||
func (w *WaapRuntimeConfig) RemoveInbandRuleByID(id int) {
|
||||
w.InBandTx.RemoveRuleByIDWithError(id)
|
||||
func (w *WaapRuntimeConfig) RemoveInbandRuleByID(id int) error {
|
||||
return w.InBandTx.RemoveRuleByIDWithError(id)
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) RemoveOutbandRuleByID(id int) {
|
||||
w.OutOfBandTx.RemoveRuleByIDWithError(id)
|
||||
func (w *WaapRuntimeConfig) CancelEvent() error {
|
||||
w.Response.SendEvent = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) SetActionnByID(id int, action string) error {
|
||||
panic("not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) RemoveOutbandRuleByID(id int) error {
|
||||
return w.OutOfBandTx.RemoveRuleByIDWithError(id)
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) SetAction(action string) error {
|
||||
w.Response.Action = action
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) SetHTTPCode(code int) error {
|
||||
w.Response.HTTPResponseCode = code
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) ProcessInBandRules(request ParsedRequest) (*corazatypes.Interruption, error) {
|
||||
|
@ -257,3 +310,22 @@ func (w *WaapRuntimeConfig) ProcessOutOfBandRules(request ParsedRequest) (*coraz
|
|||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type BodyResponse struct {
|
||||
Action string `json:"action"`
|
||||
HTTPStatus int `json:"http_status"`
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) GenerateResponse(interrupted bool) (BodyResponse, error) {
|
||||
resp := BodyResponse{}
|
||||
//if there is no interrupt, we should allow with default code
|
||||
if !interrupted {
|
||||
resp.Action = w.Config.DefaultPassAction
|
||||
resp.HTTPStatus = w.Config.PassedHTTPCode
|
||||
return resp, nil
|
||||
}
|
||||
resp.Action = w.Config.DefaultRemediation
|
||||
resp.HTTPStatus = w.Config.BlockedHTTPCode
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
|
|
@ -30,12 +30,3 @@ func GetExprWAFOptions(ctx map[string]interface{}) []expr.Option {
|
|||
}
|
||||
return baseHelpers
|
||||
}
|
||||
|
||||
func SetRulesToInband(params ...any) (any, error) {
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func SetRulesToOutOfBand(params ...any) (any, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue