Skip to content

Commit

Permalink
handle indeterminate length proxy chains - fixes #449
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron Hurt committed Feb 27, 2018
1 parent 16805a9 commit cd6b651
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 14 deletions.
29 changes: 19 additions & 10 deletions route/access_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,25 @@ func (t *Target) AccessDeniedHTTP(r *http.Request) bool {

// check xff source if present
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
// only use left-most element (client)
xff = strings.TrimSpace(strings.SplitN(xff, ",", 2)[0])
// only continue if xff differs from host
if xff != host {
if ip = net.ParseIP(xff); ip == nil {
log.Printf("[WARN] failed to parse xff address %s", xff)
}
// check xff source and return if denied
if t.denyByIP(ip) {
return true
// Trusting XFF headers sent from clients is dangerous and generally
// bad practice. Therefore, we cannot assume which if any of the elements
// is the actual client address. To try and avoid the chance of spoofed
// headers and/or loose upstream proxies we validate all elements in the header.
// Specifically AWS does not strip XFF from anonymous internet sources:
// https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html#x-forwarded-for
// See lengthy github discussion for more background: https://github.com/fabiolb/fabio/pull/449
for _, xip := range strings.Split(xff, ",") {
// ensure we only get the ip string
xip = strings.TrimSpace(xip)
// only continue if xip differs from host
if xip != host {
if ip = net.ParseIP(xip); ip == nil {
log.Printf("[WARN] failed to parse xff address %s", xip)
}
// check xff source and return if denied
if t.denyByIP(ip) {
return true
}
}
}
}
Expand Down
17 changes: 13 additions & 4 deletions route/access_rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,11 @@ func TestAccessRules_AccessDeniedHTTP(t *testing.T) {
denied bool
}{
{
desc: "denied xff and allowed remote addr",
desc: "single denied xff and allowed remote addr",
target: &Target{
Opts: map[string]string{"allow": "ip:10.0.0.0/8,ip:192.168.0.0/24"},
},
xff: "1.1.1.2, 10.11.12.13, 10.11.12.14",
xff: "10.11.12.13, 1.1.1.2, 10.11.12.14",
remote: "10.11.12.1:65500",
denied: true,
},
Expand All @@ -183,13 +183,13 @@ func TestAccessRules_AccessDeniedHTTP(t *testing.T) {
denied: true,
},
{
desc: "allowed xff and allowed remote addr",
desc: "single allowed xff and allowed remote addr",
target: &Target{
Opts: map[string]string{"allow": "ip:10.0.0.0/8,ip:192.168.0.0/24"},
},
xff: "10.11.12.13, 1.2.3.4",
remote: "192.168.0.12:65500",
denied: false,
denied: true,
},
{
desc: "denied xff and denied remote addr",
Expand All @@ -200,6 +200,15 @@ func TestAccessRules_AccessDeniedHTTP(t *testing.T) {
remote: "200.17.18.20:65500",
denied: true,
},
{
desc: "all allowed xff and allowed remote addr",
target: &Target{
Opts: map[string]string{"allow": "ip:10.0.0.0/8,ip:192.168.0.0/24"},
},
xff: "10.11.12.13, 10.110.120.130",
remote: "192.168.0.12:65500",
denied: false,
},
}

for i, tt := range tests {
Expand Down

0 comments on commit cd6b651

Please sign in to comment.