xheaders=True, X-Forwarded-For, and X-Real-Ip extravaganza

683 views
Skip to first unread message

Didip Kerabat

unread,
Apr 25, 2013, 12:08:56 PM4/25/13
to python-...@googlegroups.com
I set xheaders=True inside HTTPServer:

server = tornado.httpserver.HTTPServer(self.application, xheaders=True)

And I set both X-Real-IP and X-Forwarded-For on Nginx (This is a fairly common setup, nothing fancy).

proxy_set_header X-Real-IP         $remote_addr;
proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;


On my Nginx, $remote_addr is unfortunately the proxy's IP.
$remote_addr value is what I get from Tornado's request.remote_ip
$proxy_add_x_forwarded_for value is what I want.

Looking inside Tornado's httpserver.py, looks like it always try to get the X-Real-IP first.

if connection and connection.xheaders:
    # Squid uses X-Forwarded-For, others use X-Real-Ip
    ip = self.headers.get(
        "X-Real-Ip", self.headers.get("X-Forwarded-For", self.remote_ip))
    if netutil.is_valid_ip(ip):
        self.remote_ip = ip


So my question is:
Should Tornado try to get X-Forwarded-For first? If not then I supposed I could remove the X-Real-IP setting from Nginx.

- Didip -

Ben Darnell

unread,
Apr 25, 2013, 10:13:40 PM4/25/13
to Tornado Mailing List
Until just a few days ago we didn't support X-Forwarded-For correctly (it can be a list, but we only supported a single value), so that's one reason to favor X-Real-IP.  But other than that, there's no real basis for choosing one over the other.  

Really it was a mistake to support both headers simultaneously like this - if your proxy uses X-Forwarded-For it's trivial for an outsider to spoof whatever IP address they want by passing in their own X-Real-IP header (unless you configure your proxy to strip out any incoming X-Real-IP headers, but if you're doing that you might as well just set the header instead of clearing it).

I think the best answer is to replace xheaders=True with some mechanism to specify exactly what headers your proxy configuration uses.  This would also allow people who have multiple layers of proxies to specify which value out of the X-Forwarded-For chain is the one they want (it sounds like this might be your situation if X-Real-IP is not being set to what you want here).

-Ben




- Didip -

--
You received this message because you are subscribed to the Google Groups "Tornado Web Server" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python-tornad...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Didip Kerabat

unread,
Apr 26, 2013, 3:57:37 PM4/26/13
to python-...@googlegroups.com, b...@bendarnell.com
Got it. Based on what you say, I decided to handle the manipulation of request.remote_ip inside BaseHandler.__init__ (BaseHandler is a subclass of Tornado's RequestHandler) for now.

class BaseHandler(tornado.web.RequestHandler):
    def __init__(self, application, request, **kwargs):
        tornado.web.RequestHandler.__init__(self, application, request, **kwargs)
        forwarded_ip = self.request.headers.get("X-Forwarded-For", self.request.remote_ip)
        if tornado.netutil.is_valid_ip(forwarded_ip):
            self.request.remote_ip = forwarded_ip


- Didip -
Reply all
Reply to author
Forward
0 new messages