Implement referer blocklist to prevent hotlinking #90
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Verified against
mainat61f42e6. This is the "referer blacklist" P2 item inTODO.md; confirmed missing — theRefererheader is read only for logging (internal/middleware/middleware.go:97) and never used for any decision.The use case is hotlink protection: a third-party site embedding pixa-served images makes pixa pay the bandwidth and the origin pay the fetches, on someone else's traffic. Since signed URLs are shareable by design and long-lived until
exp, a leaked URL embedded elsewhere is a realistic drain — and withq/fitcurrently unsigned (filed separately), the amplification is worse.Naming:
TODO.mdsays "blacklist". Per the repo's inclusive-terminology convention (established whenwhitelistbecameallowlistin #41), this should bereferer_blocklistor similar. Update theTODO.mdwording in the same change.Definition of done
referer_blocklistconfig key (list of host patterns, supporting the same exact/suffix matching semantics the allowlist already uses — reuseinternal/allowlist's matcher rather than writing a second one). Strict parsing: an invalid entry aborts startup naming the key and the value, per repo policy.Referermatches is refused with 403 before any upstream fetch or cache write, so a blocked request costs nothing.Refereris treated as not-blocked (a blocklist cannot be a de facto allowlist — many legitimate clients send no referer). Document this explicitly; it is the main limitation of the feature and operators should know it is trivially bypassed by omitting the header.config.example.ymldocument the key and its limitations.make checkgreen.Note
If an allowlist model would suit better than a blocklist (refuse everything except named referers), say so before implementing — for hotlink protection an allowlist is usually the more effective shape, and the blocklist is the weaker default. Flagging the choice rather than assuming
TODO.md's wording settles it.