minor waf fixes (#2693)

This commit is contained in:
Thibault "bui" Koechlin 2024-01-03 17:19:48 +01:00 committed by GitHub
parent a504113186
commit 1c03fbe99e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 33 additions and 12 deletions

View file

@ -335,7 +335,7 @@ func (w *AppsecSource) appsecHandler(rw http.ResponseWriter, r *http.Request) {
}
// parse the request only once
parsedRequest, err := appsec.NewParsedRequestFromRequest(r)
parsedRequest, err := appsec.NewParsedRequestFromRequest(r, w.logger)
if err != nil {
w.logger.Errorf("%s", err)
rw.WriteHeader(http.StatusInternalServerError)

View file

@ -28,6 +28,7 @@ rules:
type match struct {
Type string `yaml:"type"`
Value string `yaml:"value"`
Not bool `yaml:"not,omitempty"`
}
type CustomRule struct {
@ -40,7 +41,8 @@ type CustomRule struct {
Transform []string `yaml:"transform"` //t:lowercase, t:uppercase, etc
And []CustomRule `yaml:"and,omitempty"`
Or []CustomRule `yaml:"or,omitempty"`
BodyType string `yaml:"body_type,omitempty"`
BodyType string `yaml:"body_type,omitempty"`
}
func (v *CustomRule) Convert(ruleType string, appsecRuleName string) (string, []uint32, error) {

View file

@ -18,6 +18,22 @@ func TestVPatchRuleString(t *testing.T) {
},
expected: `SecRule ARGS_GET:foo "@rx [^a-zA-Z]" "id:2203944045,phase:2,deny,log,msg:'Base Rule',tag:'crowdsec-Base Rule',t:lowercase"`,
},
{
name: "Base Rule #2",
rule: CustomRule{
Zones: []string{"METHOD"},
Match: match{Type: "startsWith", Value: "toto"},
},
expected: `SecRule REQUEST_METHOD "@beginsWith toto" "id:2759779019,phase:2,deny,log,msg:'Base Rule #2',tag:'crowdsec-Base Rule #2'"`,
},
{
name: "Base Negative Rule",
rule: CustomRule{
Zones: []string{"METHOD"},
Match: match{Type: "startsWith", Value: "toto", Not: true},
},
expected: `SecRule REQUEST_METHOD "!@beginsWith toto" "id:3966251995,phase:2,deny,log,msg:'Base Negative Rule',tag:'crowdsec-Base Negative Rule'"`,
},
{
name: "Multiple Zones",
rule: CustomRule{

View file

@ -44,6 +44,7 @@ var matchMap map[string]string = map[string]string{
"lt": "@lt",
"gte": "@ge",
"lte": "@le",
"eq": "@eq",
}
var bodyTypeMatch map[string]string = map[string]string{
@ -141,7 +142,11 @@ func (m *ModsecurityRule) buildRules(rule *CustomRule, appsecRuleName string, an
if rule.Match.Type != "" {
if match, ok := matchMap[rule.Match.Type]; ok {
r.WriteString(fmt.Sprintf(`"%s %s"`, match, rule.Match.Value))
prefix := ""
if rule.Match.Not {
prefix = "!"
}
r.WriteString(fmt.Sprintf(`"%s%s %s"`, prefix, match, rule.Match.Value))
} else {
return nil, fmt.Errorf("unknown match type '%s'", rule.Match.Type)
}

View file

@ -11,6 +11,7 @@ import (
"regexp"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
)
@ -267,7 +268,7 @@ func (r *ReqDumpFilter) ToJSON() error {
}
// Generate a ParsedRequest from a http.Request. ParsedRequest can be consumed by the App security Engine
func NewParsedRequestFromRequest(r *http.Request) (ParsedRequest, error) {
func NewParsedRequestFromRequest(r *http.Request, logger *logrus.Entry) (ParsedRequest, error) {
var err error
contentLength := r.ContentLength
if contentLength < 0 {
@ -282,26 +283,23 @@ func NewParsedRequestFromRequest(r *http.Request) (ParsedRequest, error) {
}
}
// the real source of the request is set in 'x-client-ip'
clientIP := r.Header.Get(IPHeaderName)
if clientIP == "" {
return ParsedRequest{}, fmt.Errorf("missing '%s' header", IPHeaderName)
}
// the real target Host of the request is set in 'x-client-host'
clientHost := r.Header.Get(HostHeaderName)
if clientHost == "" {
return ParsedRequest{}, fmt.Errorf("missing '%s' header", HostHeaderName)
}
// the real URI of the request is set in 'x-client-uri'
clientURI := r.Header.Get(URIHeaderName)
if clientURI == "" {
return ParsedRequest{}, fmt.Errorf("missing '%s' header", URIHeaderName)
}
// the real VERB of the request is set in 'x-client-uri'
clientMethod := r.Header.Get(VerbHeaderName)
if clientMethod == "" {
return ParsedRequest{}, fmt.Errorf("missing '%s' header", VerbHeaderName)
}
clientHost := r.Header.Get(HostHeaderName)
if clientHost == "" { //this might be empty
logger.Debugf("missing '%s' header", HostHeaderName)
}
// delete those headers before coraza process the request
delete(r.Header, IPHeaderName)