PyFu

Python Web Interfaces

Core Python Concepts

In Python web development, two major interfaces define how web applications communicate with servers which are:

  • Web Server Gateway Interface (WSGI).
  • Asynchronous Server Gateway Interface (ASGI).

Understanding both interfaces is important for selecting the right framework, deployment strategy, and server architecture for both, developers and offensive engineers.

Web Server Gateway Interface (WSGI)

WSGI is the original standard for Python web servers and frameworks.

It’s a synchronous interface that processes one request at a time per worker.

When a client sends an HTTP request, the server forwards it to the WSGI application, waits for the response, and then sends the response back to the client.

WSGI is simple, stable, and sufficient for most traditional web applications that follow the standard request-response model.

Flask is one of the most widely used Python web frameworks built on top of the WSGI interface.

WSGI applications typically require multiple workers or threads to handle high levels of concurrent traffic, since each request blocks the worker until it finishes.

Common WSGI servers include gunicorn, uWSGI, and Apache’s mod_wsgi.

Asynchronous Server Gateway Interface (ASGI)

ASGI was introduced to extend Python web applications beyond the limitations of WSGI. It supports both synchronous and asynchronous code, enabling high-concurrency, non-blocking I/O, and real-time protocols.

ASGI can handle multiple connections concurrently inside a single worker by leveraging Python’s async and await.

This allows applications to maintain thousands of open connections, making it ideal for WebSockets, streaming, background processing, and modern APIs.

Frameworks built on ASGI include FastAPI and Starlette.

ASGI is designed for modern web architectures where long-lived connections and high concurrency are required, without relying heavily on additional worker processes.

ASGI servers include uvicorn, daphne, and hypercorn.

Why these interfaces matter from an offensive security perspective

WSGI and ASGI are the layer where a request first becomes Python data, and where application-wide controls live, which makes both worth understanding before you attack anything built on top of them.

Every request arrives as a structure the application reads: the environ dict in WSGI, the scope plus receive/send channels in ASGI. Request headers, the path, the query string, and the client address all enter here, so this is the earliest point the trust boundary is crossed. It is also where middleware sits, and middleware is frequently where authentication, authorization, and security headers are enforced for the whole app at once. A flaw at this layer is systemic, not per-route. The Werkzeug interactive debugger is itself WSGI middleware wrapping the app, which is why leaving it enabled exposes the entire application to code execution (Insecure Flask Debug Mode and PIN Bypass). Global auth middleware is the FastAPI/ASGI equivalent, and a bypass there circumvents every endpoint behind it (FastAPI Middleware).

The WSGI-versus-ASGI distinction also changes the concurrency model in a way that matters offensively. WSGI handles one request per worker at a time; ASGI runs many concurrent requests inside a single worker via async/await. That shared, single-process concurrency makes async apps prone to race conditions and cross-request state leakage when developers store request data in module-level or shared objects, a class of bug that simply does not arise in the one-request-at-a-time WSGI model. Knowing which interface a target runs tells you the deployment shape, where global controls are enforced, and whether timing and race conditions are on the table.