Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

minor waf fixes #2693

Merged
merged 3 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/acquisition/modules/appsec/appsec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion pkg/appsec/appsec_rule/appsec_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ rules:
type match struct {
Type string `yaml:"type"`
Value string `yaml:"value"`
Not bool `yaml:"not,omitempty"`
}

type CustomRule struct {
Expand All @@ -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) {
Expand Down
16 changes: 16 additions & 0 deletions pkg/appsec/appsec_rule/modsec_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
7 changes: 6 additions & 1 deletion pkg/appsec/appsec_rule/modsecurity.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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)
}
Expand Down
16 changes: 7 additions & 9 deletions pkg/appsec/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"regexp"

"github.com/google/uuid"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -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 {
Expand All @@ -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)
Expand Down
Loading