Skip to content

Latest commit

 

History

History
198 lines (142 loc) · 7.55 KB

File metadata and controls

198 lines (142 loc) · 7.55 KB

FastAPI

A modern, high-performance async web framework for building APIs from Python type hints, with automatic validation and interactive OpenAPI docs.

Overview

FastAPI uses standard type hints (via Pydantic) to declare request/response models, giving automatic parsing, validation, and self-generated Swagger/OpenAPI documentation. Built on Starlette and ASGI, it handles high-concurrency async workloads well. For security tooling it's an excellent choice for building well-documented internal APIs, C2-style task servers on infrastructure you control, and data-collection services that need robust input validation.

Installation

pip install "fastapi[standard]"

Note

The [standard] extra includes the uvicorn ASGI server and the fastapi dev runner.

Basic Usage

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI(title="Lab Findings API")


class Finding(BaseModel):
    host: str
    port: int = Field(ge=1, le=65535)
    severity: str


@app.get("/health")
def health():
    return {"status": "ok"}


@app.post("/findings", status_code=201)
def create_finding(finding: Finding):
    return {"stored": finding.host, "port": finding.port}
uvicorn main:app --host 127.0.0.1 --port 8000

Type hints plus Pydantic models give request validation and an OpenAPI schema automatically — a malformed port is rejected with a 422 before your handler runs.

Important APIs

API Purpose
FastAPI(title=, docs_url=) The application
@app.get/post/put/delete(path) Route decorators
BaseModel (Pydantic) Request and response schemas with validation
Field(ge=, le=, max_length=) Field constraints
response_model= Validate and filter the response
Depends(callable) Dependency injection — auth, database sessions
HTTPException(status_code, detail) Error responses
status_code= Set the success status
BackgroundTasks Work after the response is sent
APIRouter() Split routes across modules
TestClient(app) Test harness (from Starlette)
/docs, /redoc, /openapi.json Auto-generated documentation

FastAPI runs on an ASGI server — uvicorn in development, typically behind a reverse proxy in production.

Example

A validated task/collection API:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI(title="Recon API")

class CheckIn(BaseModel):
    host: str
    user: str
    services: list[str] = []

@app.post("/checkin")
def checkin(data: CheckIn):
    return {"received": data.host, "count": len(data.services)}

# Run with:  uvicorn main:app --host 127.0.0.1 --port 8000

Output

$ curl -X POST 127.0.0.1:8000/checkin \
    -H 'Content-Type: application/json' \
    -d '{"host":"lab-01","user":"tester","services":["ssh","http"]}'
{"received":"lab-01","count":2}

Path/query parameters with automatic type validation:

from fastapi import FastAPI, HTTPException

app = FastAPI()
HOSTS = {"192.168.56.10": ["ssh", "http"]}

@app.get("/host/{ip}")
def host(ip: str, verbose: bool = False):
    if ip not in HOSTS:
        raise HTTPException(status_code=404, detail="unknown host")
    result = {"ip": ip, "services": HOSTS[ip]}
    if verbose:
        result["count"] = len(HOSTS[ip])
    return result

Output

$ curl "127.0.0.1:8000/host/192.168.56.10?verbose=true"
{"ip":"192.168.56.10","services":["ssh","http"],"count":2}

Bearer-token dependency to protect an endpoint:

from fastapi import FastAPI, Depends, HTTPException, Header

app = FastAPI()

def require_token(authorization: str = Header(default="")):
    if authorization != "Bearer s3cr3t-lab-token":
        raise HTTPException(status_code=401, detail="unauthorized")

@app.get("/tasks", dependencies=[Depends(require_token)])
def tasks():
    return {"tasks": ["scan 192.168.56.0/24", "enum dns example.com"]}

Output

$ curl -H 'Authorization: Bearer s3cr3t-lab-token' 127.0.0.1:8000/tasks
{"tasks":["scan 192.168.56.0/24","enum dns example.com"]}

Security Use Cases

  • Documented internal APIs — build tooling backends with automatic OpenAPI docs and strict input validation.
  • Task / orchestration servers — coordinate agents and jobs on authorized red-team infrastructure you own.
  • Data-collection services — accept structured check-ins/results with Pydantic models rejecting malformed input.
  • Auth-protected endpoints — use dependencies to enforce token/API-key auth on sensitive routes.
  • Rapid mock services — stand up realistic API targets for testing clients and integrations.

Warning

Deploy only on infrastructure you control. Bind to localhost or an authenticated interface, and require auth on any endpoint that returns sensitive data or triggers actions.

Common Mistakes

  • Leaving /docs and /openapi.json enabled on anything exposed — they publish your entire API surface. Set docs_url=None, redoc_url=None where that matters.
  • Returning ORM objects directly without response_model=, leaking fields such as password hashes.
  • Using dict instead of a Pydantic model, discarding the validation that is the main reason to use FastAPI.
  • Blocking calls in an async def handler — a synchronous database or network call stalls the event loop. Use def for blocking work, or an async client.
  • Permissive CORSallow_origins=["*"] with credentials enabled is a serious misconfiguration.
  • Binding to 0.0.0.0 in a lab on an untrusted network.
  • Running uvicorn --reload outside development.

Security Considerations

[!warning] Authorized use only Run listeners only on hosts and networks you control. Bind to 127.0.0.1 unless exposure is intended.

  • Validation is the security feature. Pydantic rejects malformed input before it reaches your code — define constrained models rather than accepting free-form dictionaries.
  • response_model prevents data leakage. Without it, a handler returning a database object can serialise hashes, tokens, and internal fields straight to the client.
  • The auto-generated docs are reconnaissance. /docs hands an attacker a complete map of every endpoint and schema. Disable them on anything reachable.
  • Configure CORS narrowly. Wildcard origins combined with credentials allow any site to make authenticated requests on a user's behalf.
  • Authentication is not automatic. Depends() gives you the mechanism; you still have to implement and apply it to every route that needs it.
  • Never echo request data into an error message without escaping — that is reflected XSS in the docs UI and log injection elsewhere.
  • Terminate TLS and add security headers at the reverse proxy for anything beyond a lab.

Best Practices

  • Define Pydantic models for request/response bodies so validation is automatic and explicit.
  • Use Depends() for auth, DB sessions, and shared logic instead of repeating checks.
  • Serve behind uvicorn/gunicorn with TLS; disable interactive docs (docs_url=None) in exposed deployments.
  • Raise HTTPException with proper status codes rather than returning ad-hoc error dicts.
  • Never trust client input — models validate shape, but you still authorize actions.

References

Related Topics

  • [[Flask]] — simpler, synchronous alternative for small listeners
  • [[requests]] — client for exercising your FastAPI endpoints
  • [[Readme|Python for Security Professionals]] — course home