Refuse image requests whose Referer is on referer_blocklist (closes #90) #197

Merged
clawbot merged 7 commits from issue-90-referer-blocklist into next 2026-10-04 22:24:50 +02:00
3 changed files with 17 additions and 16 deletions
Showing only changes of commit 6259832fb3 - Show all commits
+3 -3
View File
@@ -396,9 +396,9 @@ and the URL is
`images.example.com`, and `example.com` `images.example.com`, and `example.com`
An IP address is matched exactly; write an IPv6 address without brackets. An An IP address is matched exactly; write an IPv6 address without brackets. An
entry that is neither a host name (letters, digits, hyphens and dots, with at entry that is neither a host name (letters, digits, hyphens, underscores and
most one leading dot) nor an IP address, such as one with a port or a `*.` dots, with at most one leading dot) nor an IP address, such as one with a port
wildcard, aborts startup. or a `*.` wildcard, aborts startup.
### Configuration ### Configuration
+9 -9
View File
@@ -34,15 +34,15 @@ P2: security: per-IP rate limiting on the image routes
- 2026-10-04 referer blocklist (closes #90): `referer_blocklist` - 2026-10-04 referer blocklist (closes #90): `referer_blocklist`
(`PIXA_REFERER_BLOCKLIST`) lists hosts, written and matched as for (`PIXA_REFERER_BLOCKLIST`) lists hosts, written and matched as for
`allowlist_hosts` with the same matcher; an entry of either list that is `allowlist_hosts` with the same matcher; an entry of either list that is
neither a host name (letters, digits, hyphens and dots, with at most one neither a host name (letters, digits, hyphens, underscores and dots, with at
leading dot) nor an IP address, such as one with a port or a `*.` wildcard, most one leading dot) nor an IP address, such as one with a port or a `*.`
aborts startup naming the setting and the entry. Both image routes refuse a wildcard, aborts startup naming the setting and the entry. Both image routes
request whose `Referer` names a listed host with 403 and a JSON error before refuse a request whose `Referer` names a listed host with 403 and a JSON error
the signature, the cache and the upstream fetch, so it fetches nothing and is before the signature, the cache and the upstream fetch, so it fetches nothing
refused whether or not the image is cached. A request with no `Referer`, or and is refused whether or not the image is cached. A request with no
one that does not parse as a URL with a host, is served, so the list is easily `Referer`, or one that does not parse as a URL with a host, is served, so the
got around; `README.md` and `configs/config.example.yml` say so. It does not list is easily got around; `README.md` and `configs/config.example.yml` say
apply to the login and generator pages. so. It does not apply to the login and generator pages.
- 2026-10-04 fewer files in the repository root (closes #97): - 2026-10-04 fewer files in the repository root (closes #97):
`config.example.yml` moved unchanged to `configs/config.example.yml`, and `config.example.yml` moved unchanged to `configs/config.example.yml`, and
`README.md`, the comments in `internal/config/config.go` and the startup error `README.md`, the comments in `internal/config/config.go` and the startup error
+5 -4
View File
@@ -742,14 +742,15 @@ func (c *Config) validateConcurrencyLimits() error {
return nil return nil
} }
// hostNamePattern matches a host name: letters, digits, hyphens and dots, // hostNamePattern matches a host name: letters, digits, hyphens, underscores
// optionally after one leading dot. // and dots, optionally after one leading dot.
var hostNamePattern = regexp.MustCompile(`^\.?[A-Za-z0-9-][A-Za-z0-9.-]*$`) var hostNamePattern = regexp.MustCompile(`^\.?[A-Za-z0-9_-][A-Za-z0-9_.-]*$`)
// validateHostPattern checks that an entry of the named key, allowlist_hosts // validateHostPattern checks that an entry of the named key, allowlist_hosts
// or referer_blocklist, is an IP address or a host name, the host name // or referer_blocklist, is an IP address or a host name, the host name
// optionally with one leading dot for suffix matching. Anything else, such as // optionally with one leading dot for suffix matching. Anything else, such as
// a URL, a port or a "*." wildcard, can never match a host, so it is refused. // a URL, a port or a "*." wildcard, can never match a host name that resolves,
// so it is refused.
// So is "." alone: the allowlist matcher would match it against any host // So is "." alone: the allowlist matcher would match it against any host
// written with a trailing dot, which in allowlist_hosts disables URL signing. // written with a trailing dot, which in allowlist_hosts disables URL signing.
func validateHostPattern(key, host string) error { func validateHostPattern(key, host string) error {