Hi, i started using Starlette recently and for my application i need to log the client's IP address. It's important to note that i use Hypercorn as my ASGI server and it works great.
I started searching on Google how to get the IP address from Starlette, and i couldn't find it anywhere, so I searched the request object. I figured out that on the "_scope" property I could access the client IP address, but it's inside a protected member of the request object.
I don't know if there is a better way of getting it currently available on Starlette, but if there isn't i think it would be nice to have something similar to Flask's _request.remote_addr_.
Sure. As it happens request['client'] will give you a two-tuple of host, port, but it might be nice for that to have a properly documented interface, rather than just accessing it through the scope like that.
I agree it would be nice to have a properly documented interface.
It would be great to have something like this builtin:
def get_client_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
@yihuang Just use request.client. Uvicorns --proxy-headers setting will adjust the client addr to take account of proxy headers if you need that. (Other ASGI servers will also have something similar)
If you need any more complex customisation you can implement an alternate ProxyHeaders middleware. https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py
Aside: We don’t just automatically add it in always, because we can’t know which headers can be treated as “trusted”, since it’ll depend on your deployment environment.
@tomchristie That's great!
@Tom Christie commented on Mar 30, 2019, 1:34 PM GMT+4:30:
Aside: We don’t just automatically add it in always, because we can’t know which headers can be treated as “trusted”, since it’ll depend on your deployment environment.
I want to deploy on my own VPS, and run the service behind a reverse proxy (by CaddyV2). I want to disable security checks for localhost requests; Is it safe to rely on request.client.host for checking if the request is from the localhost?
Clarify one moment for me: ProxyHeadersMiddleware https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py is getting the last element from X-Forwarded-For array which is last proxy; but why would I need last proxy address (which will be an nginx address running on the current host); I want to know client's real IP where he came from.
according to the proxy_headers.py, the client port is always 0.it is not proper.
if b"x-forwarded-for" in headers:
# Determine the client address from the last trusted IP in the
# X-Forwarded-For header. We've lost the connecting client's port
# information by now, so only include the host.
x_forwarded_for = headers[b"x-forwarded-for"].decode("ascii")
host = x_forwarded_for.split(",")[-1].strip()
port = 0
scope["client"] = (host, port)
Most helpful comment
Clarify one moment for me:
ProxyHeadersMiddlewarehttps://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py is getting the last element fromX-Forwarded-Forarray which is last proxy; but why would I need last proxy address (which will be an nginx address running on the current host); I want to know client's real IP where he came from.