Question

I'm developing a website using the Python Flask framework and I now do some devving, pushing my changes to a remote dev server. I set this remote dev server up to serve the website publically using app.run(host='0.0.0.0').

This works fine, but I just don't want other people to view my website yet. For this reason I somehow want to whitelist my ip so that the dev server only serves the website to my own ip address, giving no response, 404's or some other non-useful response to other ip addresses. I can of course set up the server to use apache or nginx to actually serve the website, but I like the automatic reloading of the website on code changes for devving my website

So does anybody know of a way to do this using the built in Flask dev server? All tips are welcome!

Was it helpful?

Solution

Using just the features of Flask, you could use a before_request() hook testing the request.remote_addr attribute:

from flask import abort, request

@app.before_request
def limit_remote_addr():
    if request.remote_addr != '10.20.30.40':
        abort(403)  # Forbidden

but using a firewall rule on the server is probably the safer and more robust option.

Note that the Remote_Addr can be masked if there is a reverse proxy in between the browser and your server; be careful how you limit this and don't lock yourself out. If the proxy lives close to the server itself (like a load balancer or front-end cache), you can inspect the request.access_route list to access the actual IP address. Do this only if remote_addr itself is a trusted IP address too:

trusted_proxies = ('42.42.42.42', '82.42.82.42', '127.0.0.1')

def limit_remote_addr():
    remote = request.remote_addr
    route = list(request.access_route)
    while remote in trusted_proxies:
        remote = route.pop()

    if remote != '10.20.30.40':
        abort(403)  # Forbidden

OTHER TIPS

This IPTABLES/Netfilter rule will attend your need, dropping all incoming traffic, EXCEPT the traffic originated from your_ip_address to port 80:

$ /sbin/iptables -A INPUT -s ! your_ip_address --dport 80 -j DROP

Here's something presented on many forums, which allows localhost traffic + external access to your Flask app from your_ip_address, but reject all traffic from other IP address:

$ /sbin/iptables -A INPUT -i lo -j ACCEPT
$ /sbin/iptables -A INPUT -s your_ip_address --dport 80 -j DROP
$ /sbin/iptables -A INPUT --dport 80 -j REJECT

Although you can easily achieve the expected result via Flask (as pointed out on the elected answer), this kind of issue should be treated at the Network Layer of the Operating System. Considering that you're using a Nix-like OS, you can deny/allow incoming connections using Netfilter via IPTABLES, with rules like these.

Incoming traffic/packets, firstly, they pass through the analysis of the Kernel of your Operating System. To deny/allow traffic, from any source to specific ports, it's a job for the Firewall of the Operating System, on the Network Layer of its Kernel. If you don't have a Firewall running on your server, you should configure it.

Here's a takeaway:

  • Traffic must be treated at the Network Layer of your Operating System. Do not let application handle this task, at least on a Production environment. No one will do a best job regarding this task, than the Kernel of you Operating System (hoping that you're using a Nix-like OS). The Linux Kernel and its modules (Netfilter) are much more reliable, competent and effective to treat these kind of tasks.

I found this very helpful, but there is an easier way to do this if you have multiple ip address.

trusted_ips = ['42.42.42.42', '82.42.82.42', '127.0.0.1']

@app.before_request
def limit_remote_addr():
if request.remote_addr not in trusted_ips:
    abort(404)  # Not Found

This will check your trusted ip list and return "404 - Not Found" if the remote ip is not in the list.

You can also block specific ip by changing a few things

bad_ips = ['42.42.42.42', '82.42.82.42', '127.0.0.1']

@app.before_request
def limit_remote_addr():
if request.remote_addr in bad_ips:
    abort(404)  # Not Found

Same thing but blocks the ips in your bad_ips list

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top