Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7c2123be9 |
No files matched your search
@@ -830,12 +830,9 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
|
||||
A user's or an organisation's page has a path of one segment, such as
|
||||
`/alice`. So on any app, `q` skips these rules on every path of one
|
||||
segment, such as `/search`. But it skips 932250 only on a path made of
|
||||
the characters a name may hold: letters, digits, `-`, `_` and dots, the
|
||||
first a letter or digit. So `ls -la` is refused on
|
||||
`/login.jsp;jsessionid=abc`. `q` also keeps 932250 on a path that ends
|
||||
in a server-side script's extension, such as `/index.php`. The
|
||||
extensions are these, in upper or lower case:
|
||||
segment, such as `/search`. Such a path keeps 932250 when it ends in a
|
||||
server-side script's extension, such as `/index.php`, so `ls -la` is
|
||||
refused there. The extensions are these, in upper or lower case:
|
||||
- `.php`;
|
||||
- `.phtml`;
|
||||
- `.php5`;
|
||||
|
||||
+2324
-4
File diff suppressed because it is too large.
Load diff
File renamed without changes.
@@ -48,17 +48,7 @@ type RProxy struct {
|
||||
settings []slog.Attr
|
||||
}
|
||||
|
||||
// defaultUpstreamURL is the default of SWRP_UPSTREAM_URL.
|
||||
const defaultUpstreamURL = "http://127.0.0.1:8081"
|
||||
|
||||
// privateRanges are the private address ranges, the default trusted
|
||||
// proxies.
|
||||
const privateRanges = "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
|
||||
|
||||
var (
|
||||
errNotUpstreamURL = errors.New(
|
||||
"is not a URL with only a scheme, a host and an optional port, " +
|
||||
"such as http://127.0.0.1:8081")
|
||||
errNeedsWAFBackend = errors.New(
|
||||
"is required: it is waf's URL, such as http://waf:8080")
|
||||
errNotDisposition = errors.New("is not allow or deny")
|
||||
@@ -134,14 +124,6 @@ func (c *RProxy) LogValue() slog.Value {
|
||||
return slog.GroupValue(c.settings...)
|
||||
}
|
||||
|
||||
// appURL reads a setting that is the app's URL.
|
||||
func (e *environment) appURL(name, defaultValue string) *url.URL {
|
||||
upstream, err := parseUpstreamURL(e.value(name, defaultValue))
|
||||
e.check(name, err)
|
||||
|
||||
return upstream
|
||||
}
|
||||
|
||||
// wafBackend reads the setting that is waf's URL, which must be set.
|
||||
func (e *environment) wafBackend(name string) *url.URL {
|
||||
value := e.value(name, "")
|
||||
@@ -208,32 +190,3 @@ func parseMilliseconds(value string) (time.Duration, bool) {
|
||||
|
||||
return time.Duration(n) * time.Millisecond, true
|
||||
}
|
||||
|
||||
// parseUpstreamURL reads the app's URL: http or https, a host and an
|
||||
// optional port from 1 to 65535, and nothing else, since the request's
|
||||
// own path and query go to the app unchanged.
|
||||
func parseUpstreamURL(value string) (*url.URL, error) {
|
||||
upstream, err := url.Parse(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%q %w", value, errNotUpstreamURL)
|
||||
}
|
||||
|
||||
onlySchemeAndHost := (upstream.Scheme == "http" || upstream.Scheme == "https") &&
|
||||
upstream.Hostname() != "" && upstream.User == nil &&
|
||||
upstream.Opaque == "" &&
|
||||
(upstream.Path == "" || upstream.Path == "/") &&
|
||||
upstream.RawQuery == "" &&
|
||||
upstream.Fragment == ""
|
||||
if !onlySchemeAndHost {
|
||||
return nil, fmt.Errorf("%q %w", value, errNotUpstreamURL)
|
||||
}
|
||||
|
||||
if upstream.Port() != "" {
|
||||
port, err := strconv.ParseUint(upstream.Port(), 10, 16)
|
||||
if err != nil || port == 0 {
|
||||
return nil, fmt.Errorf("%q %w", value, errNotUpstreamURL)
|
||||
}
|
||||
}
|
||||
|
||||
return upstream, nil
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1078,14 +1078,12 @@ func TestGiteaSearchOnAUsersOrAnOrganisationsPageLetsLsThrough(t *testing.T) {
|
||||
}
|
||||
|
||||
// 932250 still applies on a path that ends in a server-side script's
|
||||
// extension or holds a character no name holds, to another field, and on
|
||||
// a path of two segments.
|
||||
// extension, to another field, and on a path of two segments.
|
||||
for _, target := range []string{
|
||||
"/index.php?q=ls%20-la",
|
||||
"/INDEX.PHP?q=ls%20-la",
|
||||
"/index%2Ephp?q=ls%20-la",
|
||||
"/search.cgi?q=ls%20-la",
|
||||
"/login.jsp;jsessionid=abc?q=ls%20-la",
|
||||
"/alice?tab=ls%20-la",
|
||||
"/alice/tools?q=ls%20-la",
|
||||
} {
|
||||
|
||||
@@ -146,12 +146,9 @@ SecRule REQUEST_FILENAME "@rx ^/[^/]+$" \
|
||||
ctl:ruleRemoveTargetById=932120;ARGS:q,\
|
||||
ctl:ruleRemoveTargetById=932260;ARGS:q"
|
||||
|
||||
# On those pages q skips 932250 too, which refused ls -la, but only on a path
|
||||
# made of the characters a user's or an organisation's name may hold. Those are
|
||||
# letters, digits, -, _ and dots, the first a letter or digit, so
|
||||
# /login.jsp;jsessionid=abc keeps 932250. A path that ends in a server-side
|
||||
# script's extension keeps it too, such as /index.php or /search.cgi.
|
||||
SecRule REQUEST_FILENAME "@rx ^/[0-9A-Za-z][-.\w]*$" \
|
||||
# On those pages q skips 932250 too, which refused ls -la. A path keeps it when
|
||||
# it ends in a server-side script's extension, such as /index.php or /search.cgi.
|
||||
SecRule REQUEST_FILENAME "@rx ^/[^/]+$" \
|
||||
"id:900606,phase:1,pass,nolog,chain"
|
||||
SecRule REQUEST_FILENAME "!@rx \.(?:php|phtml|php5|cgi|pl|py|asp|aspx|jsp)$" \
|
||||
"t:lowercase,ctl:ruleRemoveTargetById=932250;ARGS:q"
|
||||
|
||||
Reference in new issue
Block a user