Trust reverse proxies at private addresses by default (closes #198)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
With TRUSTED_PROXIES unset, the server now trusts reverse proxies in the private ranges of RFC 1918. A proxy such as traefik on a Docker network is then believed. /ip/, the home page's curl card and the request log give the client's address from X-Forwarded-For instead of the proxy's address. A list in TRUSTED_PROXIES replaces the default. TRUSTED_PROXIES set but empty trusts no proxy, so the config package reads it with os.LookupEnv. A direct client at a public address still cannot choose its address with a forged header. Model: opus-5-5
This commit is contained in:
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"os"
|
||||
"runtime"
|
||||
"slices"
|
||||
"testing"
|
||||
@@ -46,25 +47,47 @@ func TestNewRefusesInvalidPort(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewReadsTrustedProxies(t *testing.T) {
|
||||
// TestNewTrustsPrivateRangesByDefault checks that with TRUSTED_PROXIES unset
|
||||
// the trusted proxies are the private ranges of RFC 1918. Before the fix no
|
||||
// proxy was trusted, so a reverse proxy at a private address was taken for the
|
||||
// client (https://git.eeqj.de/sneak/routewatch/issues/198).
|
||||
func TestNewTrustsPrivateRangesByDefault(t *testing.T) {
|
||||
t.Setenv("PORT", "")
|
||||
t.Setenv("XDG_DATA_HOME", "")
|
||||
|
||||
// t.Setenv puts the variable back when the test ends.
|
||||
t.Setenv("TRUSTED_PROXIES", "")
|
||||
|
||||
err := os.Unsetenv("TRUSTED_PROXIES")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cfg, err := New()
|
||||
if err != nil {
|
||||
t.Fatalf("New() without TRUSTED_PROXIES: %v", err)
|
||||
}
|
||||
|
||||
if len(cfg.TrustedProxies) != 0 {
|
||||
t.Errorf("New() without TRUSTED_PROXIES: TrustedProxies = %v, want none",
|
||||
cfg.TrustedProxies)
|
||||
want := []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.0.0/8"),
|
||||
netip.MustParsePrefix("172.16.0.0/12"),
|
||||
netip.MustParsePrefix("192.168.0.0/16"),
|
||||
}
|
||||
if !slices.Equal(cfg.TrustedProxies, want) {
|
||||
t.Errorf("New() without TRUSTED_PROXIES: TrustedProxies = %v, want %v",
|
||||
cfg.TrustedProxies, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewReadsTrustedProxies checks that a list in TRUSTED_PROXIES replaces
|
||||
// the default, and that TRUSTED_PROXIES set but empty trusts no proxy.
|
||||
func TestNewReadsTrustedProxies(t *testing.T) {
|
||||
t.Setenv("PORT", "")
|
||||
t.Setenv("XDG_DATA_HOME", "")
|
||||
|
||||
t.Setenv("TRUSTED_PROXIES", "10.0.0.0/8, 192.0.2.1,2001:db8::/32")
|
||||
|
||||
cfg, err = New()
|
||||
cfg, err := New()
|
||||
if err != nil {
|
||||
t.Fatalf("New() with TRUSTED_PROXIES: %v", err)
|
||||
}
|
||||
@@ -77,6 +100,18 @@ func TestNewReadsTrustedProxies(t *testing.T) {
|
||||
if !slices.Equal(cfg.TrustedProxies, want) {
|
||||
t.Errorf("TrustedProxies = %v, want %v", cfg.TrustedProxies, want)
|
||||
}
|
||||
|
||||
t.Setenv("TRUSTED_PROXIES", "")
|
||||
|
||||
cfg, err = New()
|
||||
if err != nil {
|
||||
t.Fatalf("New() with TRUSTED_PROXIES set but empty: %v", err)
|
||||
}
|
||||
|
||||
if len(cfg.TrustedProxies) != 0 {
|
||||
t.Errorf("New() with TRUSTED_PROXIES set but empty: TrustedProxies = %v, "+
|
||||
"want none", cfg.TrustedProxies)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewRefusesInvalidTrustedProxies(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user