Walter Oggioni woggioni
  • Joined on 2024-03-17

kaya-forwarded (0.0.3)

Published 2026-09-05 09:41:38 +02:00 by woggioni in woggioni/kaya

Installation

pip install --index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple/ --extra-index-url https://pypi.org/simple kaya-forwarded

About this package

Trusted-proxy forwarded header handling for the Kaya lightweight ASGI web framework

kaya-forwarded

Trusted-proxy forwarded header handling for the Kaya web framework.

Without this package, Kaya exposes the raw socket peer address as ctx.client / ws.client and ignores Forwarded / X-Forwarded-* headers entirely (they are client-controllable and trivially spoofable when the app is directly exposed).

ForwardedHeadersMixin opts the application into honoring those headers, but only when the direct socket peer is a trusted proxy, identified by a list of trusted CIDRs/IPs.

Usage

from kaya.core import KayaApp, HttpContext
from kaya.forwarded import ForwardedHeadersMixin

app = KayaApp(mixins=[
    ForwardedHeadersMixin(trusted_proxies=['127.0.0.1', '::1', '10.0.0.0/8'])
])

@app.GET('/whoami')
async def whoami(ctx: HttpContext):
    host, port = ctx.client
    await ctx.send_str(200, f'{host}:{port}')

How it works

When a request arrives:

  1. If the socket peer IP does not belong to any trusted CIDR (or there is no peer address), the mixin leaves the context untouched — client remains the socket peer and all proxy headers are ignored.
  2. Otherwise the client address is resolved from the headers, in order:
    • Forwarded (RFC 7239): the for= entries are walked from right to left, skipping entries that are themselves trusted proxies (and unknown); the first untrusted entry is the client. This defeats spoofing when the edge proxy appends to the header (e.g. nginx with $proxy_add_x_forwarded_for), because attacker-supplied leftmost entries are never selected. A :port in the selected for= value also populates the port.
    • X-Forwarded-For: same right-to-left trusted-proxy walk; the port comes from X-Forwarded-Port when present and valid.
    • X-Forwarded-Host: first entry; port from X-Forwarded-Port as above.
  3. If none of the headers are present or usable, the socket peer is kept.

If every entry in the chain is a trusted proxy, the leftmost entry is used (the whole chain is trusted, so the leftmost is the original client).

The resolved address is exposed by wrapping the request context / websocket (the same pattern as kaya-session), so both ASGI and RSGI keep working and ctx.session from other mixins is preserved.

Note

Even with this mixin, the edge proxy should still strip or overwrite inbound Forwarded / X-Forwarded-* headers from clients — the mixin protects the application, the proxy protects the chain.

Requirements

Requires Python: >=3.10
Details
PyPI
2026-09-05 09:41:38 +02:00
6
15 KiB
Assets (2)
Versions (1) View all
0.0.3 2026-09-05