Adds ability to toggle off stripping of private addrs from XFF (#619)

* Adds ability to toggle off stripping of private addrs from XFF

* chore: spelling

Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore: refactor to flow better

Signed-off-by: Xe Iaso <me@xeiaso.net>

---------

Signed-off-by: Xe Iaso <me@xeiaso.net>
Co-authored-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
David Chandek-Stark 2025-06-09 09:33:19 -04:00 committed by GitHub
parent 6594ae0eef
commit d6e5561768
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 39 additions and 27 deletions

View File

@ -68,6 +68,7 @@ var (
extractResources = flag.String("extract-resources", "", "if set, extract the static resources to the specified folder")
webmasterEmail = flag.String("webmaster-email", "", "if set, displays webmaster's email on the reject page for appeals")
versionFlag = flag.Bool("version", false, "print Anubis version")
xffStripPrivate = flag.Bool("xff-strip-private", true, "if set, strip private addresses from X-Forwarded-For")
)
func keyFromHex(value string) (ed25519.PrivateKey, error) {
@ -336,7 +337,7 @@ func main() {
h = s
h = internal.RemoteXRealIP(*useRemoteAddress, *bindNetwork, h)
h = internal.XForwardedForToXRealIP(h)
h = internal.XForwardedForUpdate(h)
h = internal.XForwardedForUpdate(*xffStripPrivate, h)
srv := http.Server{Handler: h, ErrorLog: internal.GetFilteredHTTPLogger()}
listener, listenerUrl := setupListener(*bindNetwork, *bind)

View File

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
development
- Add `--xff-strip-private` flag/envvar to toggle skipping X-Forwarded-For private addresses or not
- Refactor challenge presentation logic to use a challenge registry
- Allow challenge implementations to register HTTP routes
- Implement a no-JS challenge method: [`metarefresh`](./admin/configuration/challenges/metarefresh.mdx) ([#95](https://github.com/TecharoHQ/anubis/issues/95))

View File

@ -50,7 +50,7 @@ For more detailed information on installing Anubis with native packages, please
Anubis uses these environment variables for configuration:
| Environment Variable | Default value | Explanation |
| :----------------------------- | :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| :----------------------------- | :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `BASE_PREFIX` | unset | If set, adds a global prefix to all Anubis endpoints. For example, setting this to `/myapp` would make Anubis accessible at `/myapp/` instead of `/`. This is useful when running Anubis behind a reverse proxy that routes based on path prefixes. |
| `BIND` | `:8923` | The network address that Anubis listens on. For `unix`, set this to a path: `/run/anubis/instance.sock` |
| `BIND_NETWORK` | `tcp` | The address family that Anubis listens on. Accepts `tcp`, `unix` and anything Go's [`net.Listen`](https://pkg.go.dev/net#Listen) supports. |
@ -72,6 +72,7 @@ Anubis uses these environment variables for configuration:
| `TARGET` | `http://localhost:3923` | The URL of the service that Anubis should forward valid requests to. Supports Unix domain sockets, set this to a URI like so: `unix:///path/to/socket.sock`. |
| `USE_REMOTE_ADDRESS` | unset | If set to `true`, Anubis will take the client's IP from the network socket. For production deployments, it is expected that a reverse proxy is used in front of Anubis, which pass the IP using headers, instead. |
| `WEBMASTER_EMAIL` | unset | If set, shows a contact email address when rendering error pages. This email address will be how users can get in contact with administrators. |
| `XFF_STRIP_PRIVATE` | `true` | If set, strip private addresses from `X-Forwarded-For` headers. To unset this, you must set `XFF_STRIP_PRIVATE=false` or `--xff-strip-private=false`. |
<details>
<summary>Advanced configuration settings</summary>

View File

@ -81,12 +81,12 @@ func XForwardedForToXRealIP(next http.Handler) http.Handler {
// XForwardedForUpdate sets or updates the X-Forwarded-For header, adding
// the known remote address to an existing chain if present
func XForwardedForUpdate(next http.Handler) http.Handler {
func XForwardedForUpdate(stripPrivate bool, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer next.ServeHTTP(w, r)
pref := XFFComputePreferences{
StripPrivate: true,
StripPrivate: stripPrivate,
StripLoopback: true,
StripCGNAT: true,
Flatten: true,

View File

@ -23,7 +23,7 @@ func TestXForwardedForUpdateIgnoreUnix(t *testing.T) {
w := httptest.NewRecorder()
XForwardedForUpdate(h).ServeHTTP(w, r)
XForwardedForUpdate(true, h).ServeHTTP(w, r)
if r.RemoteAddr != remoteAddr {
t.Errorf("wanted remoteAddr to be %s, got: %s", r.RemoteAddr, remoteAddr)
@ -43,7 +43,7 @@ func TestXForwardedForUpdateAddToChain(t *testing.T) {
w.WriteHeader(http.StatusOK)
})
srv := httptest.NewServer(XForwardedForUpdate(h))
srv := httptest.NewServer(XForwardedForUpdate(true, h))
r, err := http.NewRequest(http.MethodGet, srv.URL, nil)
if err != nil {
@ -81,6 +81,15 @@ func TestComputeXFFHeader(t *testing.T) {
},
result: "1.1.1.1,127.0.0.1",
},
{
name: "StripPrivate",
remoteAddr: "127.0.0.1:80",
origXFFHeader: "1.1.1.1,10.0.0.1",
pref: XFFComputePreferences{
StripPrivate: false,
},
result: "1.1.1.1,10.0.0.1,127.0.0.1",
},
{
name: "StripLoopback",
remoteAddr: "127.0.0.1:80",