Skip to content

Commit

Permalink
fix(ip): Do not trust forward header by default.
Browse files Browse the repository at this point in the history
  • Loading branch information
novln committed Nov 10, 2017
1 parent eaf9865 commit 34153c3
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 22 deletions.
31 changes: 17 additions & 14 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,33 @@ import (
)

// GetIP returns IP address from request.
func GetIP(r *http.Request) net.IP {
ip := r.Header.Get("X-Forwarded-For")
if ip != "" {
parts := strings.Split(ip, ",")
part := strings.TrimSpace(parts[0])
return net.ParseIP(part)
}
func GetIP(r *http.Request, trustForwardHeader ...bool) net.IP {
if len(trustForwardHeader) >= 1 && trustForwardHeader[0] {
ip := r.Header.Get("X-Forwarded-For")
if ip != "" {
parts := strings.SplitN(ip, ",", 2)
part := strings.TrimSpace(parts[0])
return net.ParseIP(part)
}

ip = r.Header.Get("X-Real-IP")
if ip != "" {
return net.ParseIP(ip)
ip = strings.TrimSpace(r.Header.Get("X-Real-IP"))
if ip != "" {
return net.ParseIP(ip)
}
}

host, _, err := net.SplitHostPort(r.RemoteAddr)
remoteAddr := strings.TrimSpace(r.RemoteAddr)
host, _, err := net.SplitHostPort(remoteAddr)
if err != nil {
return net.ParseIP(r.RemoteAddr)
return net.ParseIP(remoteAddr)
}

return net.ParseIP(host)
}

// GetIPKey extracts IP from request and returns hashed IP to use as store key.
func GetIPKey(r *http.Request) string {
return GetIP(r).String()
func GetIPKey(r *http.Request, trustForwardHeader ...bool) string {
return GetIP(r, trustForwardHeader...).String()
}

// Random return a random integer between min and max.
Expand Down
72 changes: 64 additions & 8 deletions utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,34 +37,62 @@ func TestGetIP(t *testing.T) {

scenarios := []struct {
request *http.Request
hasProxy bool
expected net.IP
}{
{
//
// Scenario #1 : RemoteAddr
// Scenario #1 : RemoteAddr without proxy.
//
request: request1,
hasProxy: false,
expected: net.ParseIP("8.8.8.8"),
},
{
//
// Scenario #2 : X-Forwarded-For
// Scenario #2 : X-Forwarded-For without proxy.
//
request: request2,
hasProxy: false,
expected: net.ParseIP("8.8.8.8"),
},
{
//
// Scenario #3 : X-Real-IP without proxy.
//
request: request3,
hasProxy: false,
expected: net.ParseIP("8.8.8.8"),
},
{
//
// Scenario #4 : RemoteAddr with proxy.
//
request: request1,
hasProxy: true,
expected: net.ParseIP("8.8.8.8"),
},
{
//
// Scenario #5 : X-Forwarded-For with proxy.
//
request: request2,
hasProxy: true,
expected: net.ParseIP("9.9.9.9"),
},
{
//
// Scenario #3 : X-Real-IP
// Scenario #6 : X-Real-IP with proxy.
//
request: request3,
hasProxy: true,
expected: net.ParseIP("6.6.6.6"),
},
}

for i, scenario := range scenarios {
message := fmt.Sprintf("Scenario #%d", (i + 1))
ip := limiter.GetIP(scenario.request)
ip := limiter.GetIP(scenario.request, scenario.hasProxy)
is.Equal(scenario.expected, ip, message)
}
}
Expand Down Expand Up @@ -94,34 +122,62 @@ func TestGetIPKey(t *testing.T) {

scenarios := []struct {
request *http.Request
hasProxy bool
expected string
}{
{
//
// Scenario #1 : RemoteAddr
// Scenario #1 : RemoteAddr without proxy.
//
request: request1,
hasProxy: false,
expected: "8.8.8.8",
},
{
//
// Scenario #2 : X-Forwarded-For without proxy.
//
request: request2,
hasProxy: false,
expected: "8.8.8.8",
},
{
//
// Scenario #3 : X-Real-IP without proxy.
//
request: request3,
hasProxy: false,
expected: "8.8.8.8",
},
{
//
// Scenario #4 : RemoteAddr without proxy.
//
request: request1,
hasProxy: true,
expected: "8.8.8.8",
},
{
//
// Scenario #2 : X-Forwarded-For
// Scenario #5 : X-Forwarded-For without proxy.
//
request: request2,
hasProxy: true,
expected: "9.9.9.9",
},
{
//
// Scenario #3 : X-Real-IP
// Scenario #6 : X-Real-IP without proxy.
//
request: request3,
hasProxy: true,
expected: "6.6.6.6",
},
}

for i, scenario := range scenarios {
message := fmt.Sprintf("Scenario #%d", (i + 1))
key := limiter.GetIPKey(scenario.request)
key := limiter.GetIPKey(scenario.request, scenario.hasProxy)
is.Equal(scenario.expected, key, message)
}
}

0 comments on commit 34153c3

Please sign in to comment.