6

Deploy a flask app with nginx + Gunicorn, and I need to get the real ip from visitors. (for Gunicorn can not get REMOTE-ADDR after nginx) I try to get client ip from X-Forwarede-for by this:

client_ip = request.headers.getlist("X-Forwarded-For")[0]

Sometimes I get client_ip correctly like this:

x-forwarded-for: 62.211.19.218

But sometimes I get client_ip wrong like this - combined with a proxy ip address (visit from some different Browsers):

x-forwarded-for: 62.211.19.218, 177.168.159.85

How to get only the first client ip (without the proxy address 177.168.159.85) when nginx forwards two ip addresses to App?

rogwan
  • 177
  • 1
  • 4
  • 12

1 Answers1

7

Generally X-FORWARDED-FOR forms like below:

X-Forwarded-For: client1, proxy1, proxy2, ...

But remember, you should not trust X-Forwarded-For, or any other header values, because they are manipulatable by untrusted proxies or something...

If you use nginx as a reverse proxy, you can also check request.environ['HTTP_X_REAL_IP']


EDIT

According to flask documentation, client_ip = request.access_route[0] will be your answer. It will return ip addresses in X-FORWARDED-FOR. Check this wrekzeug/wrapper.py source code

@cached_property
def access_route(self):
    """If a forwarded header exists this is a list of all ip addresses
    from the client ip to the last proxy server.
    """
    if 'HTTP_X_FORWARDED_FOR' in self.environ:
        addr = self.environ['HTTP_X_FORWARDED_FOR'].split(',')
        return self.list_storage_class([x.strip() for x in addr])
    elif 'REMOTE_ADDR' in self.environ:
        return self.list_storage_class([self.environ['REMOTE_ADDR']])
    return self.list_storage_class()

Note that some http servers append localhost or local ip address into first item of access_route list.

changhwan
  • 1,000
  • 8
  • 22
  • 1
    The problem is that I've tried to get the first client1 ip by request.headers.getlist("X-Forwarded-For")[0], [0] should get the first client1 from the forms, but sometimes it get the first client1 followed with proxy1. So that another App can not analyze these two combined IPs string. Yes, I've already gotten by request.environ.get['HTTP_X_REAL_IP'], thank you! – rogwan Nov 20 '15 at 10:31
  • @rogwan Then why don't you just parce result using split by `,`? – changhwan Nov 24 '15 at 03:59
  • @mromo I've tried this: > `client_ip = request.headers.getlist("X-Forwarded-For").split(',')[0]` but it does not work... – rogwan Nov 25 '15 at 14:34
  • Append new answer, check it. also in your last comment, replacing `getlist` to `get` will work. – changhwan Nov 27 '15 at 06:00
  • Perfect! using 'get' instead of 'getlist' works well, thank you for pointing out this mistake precisely. – rogwan Nov 27 '15 at 16:06