Skip to content

Commit 45ea1f5

Browse files
author
Alex Yang
committed
Merged PR 2671382: MatchVariable Selectors should be applied case-insensitively
To keep behavioral parity between AzWAF and ModSecurity, we should apply the `Selector` field in `MatchVariable` case-insensitively. This applies to all 3 `MatchVariables` This is achieved by constructing a new key into the `conditionGroup` map, which converts the `Selector` in the `MatchVariable` struct to lower-case. PR URL: https://msazure.visualstudio.com/DefaultCollection/One/_git/Networking-Azwaf/pullrequest/2671382 Related work items: #6427995, #6428248
1 parent f730a71 commit 45ea1f5

File tree

4 files changed

+98
-3
lines changed

4 files changed

+98
-3
lines changed

customrule/engine.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,14 @@ func (f *customRuleEngineFactoryImpl) NewEngine(customRuleConfig waf.CustomRuleC
5656
}
5757

5858
mv := matchVariable{m.VariableName(), m.Selector()}
59+
cgKey := matchVariableWithLowerCaseSelector(mv)
5960

6061
// Use existing struct for this MatchVariable or create new one if not yet created
6162
var cwsmv *conditionsWithSameMatchVar
6263
var ok bool
63-
if cwsmv, ok = engine.conditionGroups[mv]; !ok {
64+
if cwsmv, ok = engine.conditionGroups[cgKey]; !ok {
6465
cwsmv = &conditionsWithSameMatchVar{}
65-
engine.conditionGroups[mv] = cwsmv
66+
engine.conditionGroups[cgKey] = cwsmv
6667
}
6768

6869
// Use existing struct for this transformation-pipeline or create new one if not yet created
@@ -387,7 +388,8 @@ type scanResults struct {
387388
}
388389

389390
func (e *customRuleEvaluationImpl) scanTarget(m matchVariable, content string, results *scanResults) (err error) {
390-
cg, ok := e.engine.conditionGroups[m]
391+
cgKey := matchVariableWithLowerCaseSelector(m)
392+
cg, ok := e.engine.conditionGroups[cgKey]
391393
if !ok {
392394
// There were no conditions that needed this target
393395
return
@@ -549,6 +551,10 @@ func (e *customRuleEvaluationImpl) scanCookies(c string, results *scanResults) (
549551
return
550552
}
551553

554+
func matchVariableWithLowerCaseSelector(m matchVariable) matchVariable {
555+
return matchVariable{variableName: m.variableName, selector: strings.ToLower(m.selector)}
556+
}
557+
552558
func applyTransformations(s string, transformations []string) string {
553559
// TODO implement a trie for caching already done transformations
554560
for _, t := range transformations {

customrule/eval_postargs_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,39 @@ func TestPostArgsEqualsBlockPositive(t *testing.T) {
6363
assert.Equal(waf.Block, decision)
6464
}
6565

66+
func TestPostArgsWithDifferentCasingEqualsBlockPositive(t *testing.T) {
67+
assert := assert.New(t)
68+
logger := testutils.NewTestLogger(t)
69+
70+
// Arrange
71+
content := "firstName=john&lastName=travolta"
72+
req := &mockWafHTTPRequest{
73+
uri: "/",
74+
method: "POST",
75+
headers: []waf.HeaderPair{
76+
&mockHeaderPair{k: "Content-Type", v: "application/x-www-form-urlencoded"},
77+
&mockHeaderPair{k: "Content-Length", v: fmt.Sprint(len(content))},
78+
},
79+
body: content,
80+
}
81+
engine, resLog, err := newEngineWithCustomRules(postArgsEqualsBlockRule)
82+
if err != nil {
83+
t.Fatalf("Got unexpected error: %s", err)
84+
}
85+
86+
// Act
87+
eval := engine.NewEvaluation(logger, resLog, req, waf.URLEncodedBody)
88+
defer eval.Close()
89+
err = eval.ScanHeaders()
90+
err = eval.ScanBodyField(waf.URLEncodedContent, "FIRSTNAME", "john")
91+
err = eval.ScanBodyField(waf.URLEncodedContent, "LASTNAME", "travolta")
92+
decision := eval.EvalRules()
93+
94+
// Assert
95+
assert.Nil(err)
96+
assert.Equal(waf.Block, decision)
97+
}
98+
6699
func TestPostArgsEqualsBlockNegative(t *testing.T) {
67100
assert := assert.New(t)
68101
logger := testutils.NewTestLogger(t)

customrule/eval_requestcookies_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,34 @@ func TestRequestCookiesContainsBlockPositive(t *testing.T) {
5757
assert.Equal(waf.Block, decision)
5858
}
5959

60+
func TestRequestCookiesWithDifferentCasingContainsBlockPositive(t *testing.T) {
61+
assert := assert.New(t)
62+
logger := testutils.NewTestLogger(t)
63+
64+
// Arrange
65+
req := &mockWafHTTPRequest{
66+
uri: "/",
67+
method: "GET",
68+
headers: []waf.HeaderPair{
69+
&mockHeaderPair{k: "Cookie", v: "The_Oracles_Special_Recipe=neo+is+the+one; the_matrix_cookie_house=agent+smith"},
70+
},
71+
}
72+
engine, resLog, err := newEngineWithCustomRules(requestCookiesContainsBlockRule)
73+
if err != nil {
74+
t.Fatalf("Got unexpected error: %s", err)
75+
}
76+
77+
// Act
78+
eval := engine.NewEvaluation(logger, resLog, req, waf.OtherBody)
79+
defer eval.Close()
80+
err = eval.ScanHeaders()
81+
decision := eval.EvalRules()
82+
83+
// Assert
84+
assert.Nil(err)
85+
assert.Equal(waf.Block, decision)
86+
}
87+
6088
func TestRequestCookiesContainsBlockNegative(t *testing.T) {
6189
assert := assert.New(t)
6290
logger := testutils.NewTestLogger(t)

customrule/eval_requestheaders_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,34 @@ func TestRequestHeadersContainsBlockPositive(t *testing.T) {
5858
assert.Equal(waf.Block, decision)
5959
}
6060

61+
func TestRequestHeadersWithDifferentCasingContainsBlockPositive(t *testing.T) {
62+
assert := assert.New(t)
63+
logger := testutils.NewTestLogger(t)
64+
65+
// Arrange
66+
req := &mockWafHTTPRequest{
67+
uri: "/",
68+
method: "GET",
69+
headers: []waf.HeaderPair{
70+
&mockHeaderPair{k: "x-first-name", v: "John"},
71+
&mockHeaderPair{k: "x-last-name", v: "Travolta"},
72+
},
73+
}
74+
engine, resLog, err := newEngineWithCustomRules(requestHeadersContainsBlockRule)
75+
if err != nil {
76+
t.Fatalf("Got unexpected error: %s", err)
77+
}
78+
79+
// Act
80+
eval := engine.NewEvaluation(logger, resLog, req, waf.OtherBody)
81+
err = eval.ScanHeaders()
82+
decision := eval.EvalRules()
83+
84+
// Assert
85+
assert.Nil(err)
86+
assert.Equal(waf.Block, decision)
87+
}
88+
6189
func TestRequestHeadersContainsBlockNegative(t *testing.T) {
6290
assert := assert.New(t)
6391
logger := testutils.NewTestLogger(t)

0 commit comments

Comments
 (0)