wip
This commit is contained in:
parent
6ac0a9ef9d
commit
65884fb4be
2 changed files with 154 additions and 1 deletions
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/corazawaf/coraza/v3"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/waf"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
@ -110,7 +111,23 @@ func (w *WafSource) Configure(yamlConfig []byte, logger *log.Entry) error {
|
|||
Handler: w.mux,
|
||||
}
|
||||
|
||||
waf, err := coraza.NewWAF(coraza.NewWAFConfig())
|
||||
crowdsecWafConfig := waf.NewWafConfig()
|
||||
|
||||
err = crowdsecWafConfig.LoadWafRules()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot load WAF rules: %w", err)
|
||||
}
|
||||
|
||||
var rules string
|
||||
|
||||
for _, rule := range crowdsecWafConfig.InbandRules {
|
||||
rules += rule.String() + "\n"
|
||||
}
|
||||
|
||||
w.logger.Infof("Loading rules %+v", rules)
|
||||
|
||||
waf, err := coraza.NewWAF(coraza.NewWAFConfig().WithDirectives(rules))
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot create WAF")
|
||||
|
|
136
pkg/waf/waf.go
Normal file
136
pkg/waf/waf.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
package waf
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/antonmedv/expr"
|
||||
"github.com/antonmedv/expr/vm"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwhub"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Hook struct {
|
||||
Filter string `yaml:"filter"`
|
||||
FilterExpr *vm.Program `yaml:"-"`
|
||||
OnSuccess string `yaml:"on_success"`
|
||||
Apply []string `yaml:"apply"`
|
||||
ApplyExpr []*vm.Program
|
||||
}
|
||||
|
||||
type WafRule struct {
|
||||
SecLangFilesRules []string `yaml:"seclang_files_rules"`
|
||||
SecLangRules []string `yaml:"seclang_rules"`
|
||||
OnLoad []Hook `yaml:"on_load"`
|
||||
PreEval []Hook `yaml:"pre_eval"`
|
||||
OnMatch []Hook `yaml:"on_match"`
|
||||
MergedRules []string `yaml:"-"`
|
||||
OutOfBand bool `yaml:"-"`
|
||||
}
|
||||
|
||||
type WafConfig struct {
|
||||
InbandRules []WafRule
|
||||
OutOfBandRules []WafRule
|
||||
}
|
||||
|
||||
func buildHook(hook Hook) (Hook, error) {
|
||||
if hook.Filter != "" {
|
||||
program, err := expr.Compile(hook.Filter) //FIXME: opts
|
||||
if err != nil {
|
||||
log.Errorf("unable to compile filter %s : %s", hook.Filter, err)
|
||||
return Hook{}, err
|
||||
}
|
||||
hook.FilterExpr = program
|
||||
}
|
||||
for _, apply := range hook.Apply {
|
||||
program, err := expr.Compile(apply) //FIXME: opts
|
||||
if err != nil {
|
||||
log.Errorf("unable to compile apply %s : %s", apply, err)
|
||||
return Hook{}, err
|
||||
}
|
||||
hook.ApplyExpr = append(hook.ApplyExpr, program)
|
||||
}
|
||||
return hook, nil
|
||||
}
|
||||
|
||||
func (w *WafConfig) LoadWafRules() error {
|
||||
var files []string
|
||||
for _, hubWafRuleItem := range cwhub.GetItemMap(cwhub.WAF_RULES) {
|
||||
if hubWafRuleItem.Installed {
|
||||
files = append(files, hubWafRuleItem.LocalPath)
|
||||
}
|
||||
}
|
||||
log.Infof("Loading %d waf files", len(files))
|
||||
for _, file := range files {
|
||||
|
||||
fileContent, err := os.ReadFile(file) //FIXME: actually read from datadir
|
||||
if err != nil {
|
||||
log.Errorf("unable to read file %s : %s", file, err)
|
||||
continue
|
||||
}
|
||||
wafRule := WafRule{}
|
||||
err = yaml.Unmarshal(fileContent, &wafRule)
|
||||
if err != nil {
|
||||
log.Errorf("unable to unmarshal file %s : %s", file, err)
|
||||
continue
|
||||
}
|
||||
if wafRule.SecLangFilesRules != nil {
|
||||
for _, rulesFile := range wafRule.SecLangFilesRules {
|
||||
c, err := os.ReadFile(rulesFile)
|
||||
if err != nil {
|
||||
log.Errorf("unable to read file %s : %s", rulesFile, err)
|
||||
continue
|
||||
}
|
||||
wafRule.MergedRules = append(wafRule.MergedRules, string(c))
|
||||
}
|
||||
}
|
||||
if wafRule.SecLangRules != nil {
|
||||
wafRule.MergedRules = append(wafRule.MergedRules, wafRule.SecLangRules...)
|
||||
}
|
||||
|
||||
//compile hooks
|
||||
for _, hook := range wafRule.OnLoad {
|
||||
hook, err = buildHook(hook)
|
||||
if err != nil {
|
||||
log.Errorf("unable to build hook %s : %s", hook.Filter, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for _, hook := range wafRule.PreEval {
|
||||
hook, err = buildHook(hook)
|
||||
if err != nil {
|
||||
log.Errorf("unable to build hook %s : %s", hook.Filter, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for _, hook := range wafRule.OnMatch {
|
||||
hook, err = buildHook(hook)
|
||||
if err != nil {
|
||||
log.Errorf("unable to build hook %s : %s", hook.Filter, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if wafRule.MergedRules != nil {
|
||||
if wafRule.OutOfBand {
|
||||
w.OutOfBandRules = append(w.OutOfBandRules, wafRule)
|
||||
} else {
|
||||
w.InbandRules = append(w.InbandRules, wafRule)
|
||||
}
|
||||
} else {
|
||||
log.Warnf("no rules found in file %s ??", file)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewWafConfig() *WafConfig {
|
||||
return &WafConfig{}
|
||||
}
|
||||
|
||||
func (w *WafRule) String() string {
|
||||
return strings.Join(w.MergedRules, "\n")
|
||||
}
|
Loading…
Reference in a new issue