I just deployed a Flask app on Webfaction and I've noticed that request.remote_addr
is always 127.0.0.1
. which is of course isn't of much use.
How can I get the real IP address of the user in Flask on Webfaction?
Thanks!
How to Find the IP Address Of a User in Flask? Whenever a client requests a page - they send an HTTP GET request, with a certain payload. Amongst other information - their distinctive IP address is included. In Flask - every route has access to the request variable, which represents the incoming request from the user.
HTTP_X_FORWARDED_FOR is often used to detect the client IP address, but without any additional checks, this can lead to security issues, especially when this IP is later used for authentication or in SQL queries without sanitization.
REMOTE_HOST pertains to the hostname of the client (i.e. the computer making the request). REMOTE_ADDR refers to the IP address of the client. There would be times when the hostname is unresolvable so the REMOTE_HOST will return the REMOTE_ADDR or the IP address instead. Follow this answer to receive notifications.
If there is a proxy in front of Flask, then something like this will get the real IP in Flask:
if request.headers.getlist("X-Forwarded-For"):
ip = request.headers.getlist("X-Forwarded-For")[0]
else:
ip = request.remote_addr
Update: Very good point mentioned by Eli in his comment. There could be some security issues if you just simply use this. Read Eli's post to get more details.
Flask's documentation is pretty specific about recommended reverse proxy server setup:
If you deploy your application using one of these [WSGI] servers behind an HTTP [reverse] proxy you will need to rewrite a few headers in order for the application to work [properly]. The two problematic values in the WSGI environment usually are
REMOTE_ADDR
andHTTP_HOST
... Werkzeug ships a fixer that will solve some common setups, but you might want to write your own WSGI middleware for specific setups.
And also about security consideration:
Please keep in mind that it is a security issue to use such a middleware in a non-proxy setup because it will blindly trust the incoming headers which might be forged by malicious clients.
The suggested code (that installs the middleware) that will make request.remote_addr
return client IP address is:
from werkzeug.contrib.fixers import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, num_proxies=1)
Note num_proxies
which is 1
by default. It's the number of proxy servers in front of the app.
The actual code is as follows (lastest werkzeug==0.14.1
at the time of writing):
def get_remote_addr(self, forwarded_for):
if len(forwarded_for) >= self.num_proxies:
return forwarded_for[-self.num_proxies]
Webfaction's documentation about Accessing REMOTE_ADDR
says:
...the IP address is available as the first IP address in the comma separated list in the
HTTP_X_FORWARDED_FOR
header.
They don't say what they do when a client request already contains X-Forwarded-For
header, but following common sense I would assume they replace it. Thus for Webfaction num_proxies
should be set to 0
.
Nginx is more explicit about it's $proxy_add_x_forwarded_for
:
the “X-Forwarded-For” client request header field with the
$remote_addr
variable appended to it, separated by a comma. If the “X-Forwarded-For” field is not present in the client request header, the$proxy_add_x_forwarded_for
variable is equal to the$remote_addr
variable.
For Nginx in front of the app num_proxies
should be left at default 1
.
Rewriting the Ignas's answer:
headers_list = request.headers.getlist("X-Forwarded-For")
user_ip = headers_list[0] if headers_list else request.remote_addr
Remember to read Eli's post about spoofing considerations.
You can use request.access_route
to access list of ip :
if len(request.access_route) > 1:
return request.access_route[-1]
else:
return request.access_route[0]
Update:
You can just write this:
return request.access_route[-1]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With