tornado icon indicating copy to clipboard operation
tornado copied to clipboard

Add method to get client's claimed IP

Open bdarnell opened this issue 12 years ago • 6 comments

The HTTPRequest.remote_ip field is intended to contain a trustworthy equivalent of the TCP-level remote address, so it accepts only a single X-Forwarded-For hop, and only when configured to do so. For some purposes (e.g. geolocation), it is useful to take whatever IP address the client claims to be using even through a chain of untrusted proxies. There should be some method to return the first public IP address from X-Forwarded-For.

bdarnell avatar Sep 22 '13 16:09 bdarnell

I agree that remote_ip should return the "true" remote IP (which should be localhost in most proxied setups) and there should be a getter (e.g. the suggested get_claimed_ip() to get the actual client IP.

That said, there is another (maybe not so uncommon) example when using Cloudflare - these guys expose the client IP address via the CF-Connecting-IP header - there is a KB article explaining how to setup Nginx to use that header from trusted proxies only to determine the real_ip.

This allows Nginx to work and populate logs with actual client IPs and for logging/analytics purposes it would be great if I could tell Tornado which header to use for the "real ip" to appear in logs and for other purposes.

PatTheMav avatar May 30 '17 20:05 PatTheMav

This issue description is a bit out of date. According to http://www.tornadoweb.org/en/stable/httpserver.html#http-server

By default, when parsing the X-Forwarded-For header, Tornado will select the last (i.e., the closest) address on the list of hosts as the remote host IP address. To select the next server in the chain, a list of trusted downstream hosts may be passed as the trusted_downstream argument. These hosts will be skipped when parsing the X-Forwarded-For header.

That's very similar to what nginx can do (you just can't customize the header to look at, it's just X-Forwarded-For or X-Real-IP).

ploxiln avatar May 30 '17 20:05 ploxiln

*sigh* yeah looks like I had a severe case of brain-lag - FWIW setting xheaders to true seems to be enough. Nginx doesn't add itself to the X-Forwarded-For header (dunno if that's due to the real_ip module) so not even the trusted_upstreams setting is needed.

Also: Cloudflare supports its own header as well as X-Forwarded-For..

PatTheMav avatar May 30 '17 20:05 PatTheMav

The issue description is still valid. The xheaders and trusted_downstream options let you find the IP via which the request entered your network. The X-Forwarded-For header may contain additional untrusted information from external proxies; this issue proposes to expose the source address claimed by that untrusted proxy chain for use cases where a malicious client or proxy is not a concern. (For example, the untrusted source IP may be useful for geotargeting purposes, since honest proxies that use this field will get you closer to the user's true location, while the harm caused by a lying proxy is limited)

bdarnell avatar Jun 03 '17 17:06 bdarnell

I'm initiating my server using this: tornado.web.Application([..routes..], **settings) . But all the xheader examples are tornado.httpserver.HTTPServer(). How can I set xheaders=True in a tornado.web.Application() initiation?

answerquest avatar Nov 30 '20 06:11 answerquest

You can pass it e.g. using kwargs on the listen method:

        application = cls(options)
        application.listen(options.port, xheaders=True)

PatTheMav avatar Nov 30 '20 21:11 PatTheMav