Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Use the first IP address in HTTP_X_FORWARDED_FOR as the originating IP #598

Closed
wants to merge 1 commit into from

2 participants

@jasonbosco

According to the W3C guidelines for the X-Forwarded-For HTTP header:

proxies should add the IP address of the initiator of the request to the end of a comma separated list in an X-Forwarded-For HTTP header field

So as a request goes through multiple proxies, the IP addresses of the proxies get appended to the end of the list in X-Forwarded-For. So the first IP address in this list is the originating client IP.

Currently, Rack::Request#ip returns the last IP address in the forwarded_ips list which is actually the IP address of the last proxy. This pull request fixes this issue by returning the first IP address in the list.

@raggi
Owner

This is client IP not originating IP.

Convention for transparent clients is to fulfill the REMOTE_ADDR header at the boundary.

Altering the semantics of this method will alter various security middleware functionality.

I would accept an "originating_ip" method addition instead.

@raggi raggi closed this
@kushkella kushkella referenced this pull request in intridea/grape
Closed

remote_ip method for request #648

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 17 additions and 17 deletions.
  1. +1 −1  lib/rack/request.rb
  2. +16 −16 test/spec_request.rb
View
2  lib/rack/request.rb
@@ -365,7 +365,7 @@ def ip
return client_ip if forwarded_ips.include?(client_ip)
end
- return reject_trusted_ip_addresses(forwarded_ips).last || @env["REMOTE_ADDR"]
+ return reject_trusted_ip_addresses(forwarded_ips).first || @env["REMOTE_ADDR"]
end
protected
View
32 test/spec_request.rb
@@ -976,47 +976,47 @@
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
res.body.should.equal '3.4.5.6'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,3.4.5.6'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,unknown'
res.body.should.equal '3.4.5.6'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,192.168.0.1'
res.body.should.equal '3.4.5.6'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,10.0.0.1'
res.body.should.equal '3.4.5.6'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => ' 3.4.5.6, 10.0.0.1, 10.0.0.1'
res.body.should.equal '3.4.5.6'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '127.0.0.1, 3.4.5.6'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,127.0.0.1'
res.body.should.equal '3.4.5.6'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,unknown'
res.body.should.equal 'unknown'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'other,unknown,192.168.0.1'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,unknown,other'
res.body.should.equal 'unknown'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,localhost,192.168.0.1'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,localhost,unknown'
res.body.should.equal 'unknown'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '172.31.4.4, 10.0.0.1, 3.4.5.6, 9.9.9.9'
res.body.should.equal '3.4.5.6'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '::1,2620:0:1c00:0:812c:9583:754b:ca11'
- res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
-
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,::1'
res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'fd5b:982e:9130:247f:0000:0000:0000:0000,2620:0:1c00:0:812c:9583:754b:ca11'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '::1,2620:0:1c00:0:812c:9583:754b:ca11'
res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,fd5b:982e:9130:247f:0000:0000:0000:0000'
res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'fd5b:982e:9130:247f:0000:0000:0000:0000,2620:0:1c00:0:812c:9583:754b:ca11'
+ res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
+
res = mock.get '/',
- 'HTTP_X_FORWARDED_FOR' => '1.1.1.1, 127.0.0.1',
+ 'HTTP_X_FORWARDED_FOR' => '127.0.0.1,1.1.1.1',
'HTTP_CLIENT_IP' => '1.1.1.1'
res.body.should.equal '1.1.1.1'
@@ -1026,10 +1026,10 @@
'HTTP_CLIENT_IP' => '2.2.2.2'
res.body.should.equal '1.1.1.1'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '9.9.9.9,8.8.8.8'
res.body.should.equal '9.9.9.9'
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, fe80::202:b3ff:fe1e:8329'
+ res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'fe80::202:b3ff:fe1e:8329,8.8.8.8'
res.body.should.equal 'fe80::202:b3ff:fe1e:8329'
# Unix Sockets
Something went wrong with that request. Please try again.