Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FastAPI how to allow endpoint access for specific IP only?

Tags:

fastapi

How to limit endpoint access only to specific IPs with FastAPI?

like image 319
MrFoot fifer Avatar asked Mar 30 '21 09:03

MrFoot fifer


People also ask

How do I find my client IP address on FastAPI?

You can also use --forwarded-allow-ips='127.0. 0.1,[::1]' to catch both ip4 and ip6 on localhost. --proxy-headers / --no-proxy-headers - Enable/Disable X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port to populate remote address info.

What is IP allow list?

A Login IP Allowlist includes a range of IP addresses you define that indicates what IP addresses can access your account to prevent unauthorized IP addresses from logging into your account. Allowlisted IP addresses ranges can access the application.

How many requests can FastAPI handle?

FastAPI (Async) - Python FastAPI in asynchronous mode clocks in at ~228 requests per second.

How can I send request in FastAPI?

Use the Request object directly For that you need to access the request directly. By declaring a path operation function parameter with the type being the Request FastAPI will know to pass the Request in that parameter. Note that in this case, we are declaring a path parameter beside the request parameter.


Video Answer


2 Answers

The accepted answer makes use of the TrustedHostMiddleware but that can be easily spoofed using a reverse proxy, i.e. using NGINX or using any other technique. In my opinion, validating IP address in a custom middleware is more secure:

from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse


app = FastAPI()

# Whitelisted IPs
WHITELISTED_IPS = []

@app.middleware('http')
async def validate_ip(request: Request, call_next):
    # Get client IP
    ip = str(request.client.host)
    
    # Check if IP is allowed
    if ip not in WHITELISTED_IPS:
        data = {
            'message': f'IP {ip} is not allowed to access this resource.'
        }
        return JSONResponse(status_code=status.HTTP_400_BAD_REQUEST, content=data)

    # Proceed if IP is allowed
    return await call_next(request)

I'd maintain a list of whitelisted IPs and then I'd compare the client IP to the list and will return a 400 Bad Request error if the IP is not in the whitelisted IPs list.

like image 191
Rehmat Avatar answered Nov 01 '22 08:11

Rehmat


FastAPI provides a TrustedHostMiddleware that:

Enforces that all incoming requests have a correctly set Host header, in order to guard against HTTP Host Header attacks.

from fastapi import FastAPI from fastapi.middleware.trustedhost import TrustedHostMiddleware

app = FastAPI()

app.add_middleware(
    TrustedHostMiddleware, allowed_hosts=["example.com","*.example.com"] 
)


@app.get("/") async def main():
    return {"message": "Hello World"}

The following arguments are supported:

  • allowed_hosts - A list of domain names that should be allowed as hostnames. Wildcard domains such as *.example.com are supported for matching subdomains to allow any hostname either use allowed_hosts=["*"] or omit the middleware.

If an incoming request does not validate correctly then a 400 response will be sent.

Another solution would be to compose an IP whitelist for your deployment medium (ex: k8).

like image 26
John Moutafis Avatar answered Nov 01 '22 09:11

John Moutafis