minor waf fixes (#2693)
This commit is contained in:
parent
a504113186
commit
1c03fbe99e
|
@ -335,7 +335,7 @@ func (w *AppsecSource) appsecHandler(rw http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the request only once
|
// parse the request only once
|
||||||
parsedRequest, err := appsec.NewParsedRequestFromRequest(r)
|
parsedRequest, err := appsec.NewParsedRequestFromRequest(r, w.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.logger.Errorf("%s", err)
|
w.logger.Errorf("%s", err)
|
||||||
rw.WriteHeader(http.StatusInternalServerError)
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
|
|
|
@ -28,6 +28,7 @@ rules:
|
||||||
type match struct {
|
type match struct {
|
||||||
Type string `yaml:"type"`
|
Type string `yaml:"type"`
|
||||||
Value string `yaml:"value"`
|
Value string `yaml:"value"`
|
||||||
|
Not bool `yaml:"not,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomRule struct {
|
type CustomRule struct {
|
||||||
|
@ -40,6 +41,7 @@ type CustomRule struct {
|
||||||
Transform []string `yaml:"transform"` //t:lowercase, t:uppercase, etc
|
Transform []string `yaml:"transform"` //t:lowercase, t:uppercase, etc
|
||||||
And []CustomRule `yaml:"and,omitempty"`
|
And []CustomRule `yaml:"and,omitempty"`
|
||||||
Or []CustomRule `yaml:"or,omitempty"`
|
Or []CustomRule `yaml:"or,omitempty"`
|
||||||
|
|
||||||
BodyType string `yaml:"body_type,omitempty"`
|
BodyType string `yaml:"body_type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"`,
|
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",
|
name: "Multiple Zones",
|
||||||
rule: CustomRule{
|
rule: CustomRule{
|
||||||
|
|
|
@ -44,6 +44,7 @@ var matchMap map[string]string = map[string]string{
|
||||||
"lt": "@lt",
|
"lt": "@lt",
|
||||||
"gte": "@ge",
|
"gte": "@ge",
|
||||||
"lte": "@le",
|
"lte": "@le",
|
||||||
|
"eq": "@eq",
|
||||||
}
|
}
|
||||||
|
|
||||||
var bodyTypeMatch map[string]string = map[string]string{
|
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 rule.Match.Type != "" {
|
||||||
if match, ok := matchMap[rule.Match.Type]; ok {
|
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 {
|
} else {
|
||||||
return nil, fmt.Errorf("unknown match type '%s'", rule.Match.Type)
|
return nil, fmt.Errorf("unknown match type '%s'", rule.Match.Type)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
log "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
|
// 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
|
var err error
|
||||||
contentLength := r.ContentLength
|
contentLength := r.ContentLength
|
||||||
if contentLength < 0 {
|
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)
|
clientIP := r.Header.Get(IPHeaderName)
|
||||||
if clientIP == "" {
|
if clientIP == "" {
|
||||||
return ParsedRequest{}, fmt.Errorf("missing '%s' header", IPHeaderName)
|
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)
|
clientURI := r.Header.Get(URIHeaderName)
|
||||||
if clientURI == "" {
|
if clientURI == "" {
|
||||||
return ParsedRequest{}, fmt.Errorf("missing '%s' header", URIHeaderName)
|
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)
|
clientMethod := r.Header.Get(VerbHeaderName)
|
||||||
if clientMethod == "" {
|
if clientMethod == "" {
|
||||||
return ParsedRequest{}, fmt.Errorf("missing '%s' header", VerbHeaderName)
|
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 those headers before coraza process the request
|
||||||
delete(r.Header, IPHeaderName)
|
delete(r.Header, IPHeaderName)
|
||||||
|
|
Loading…
Reference in a new issue