kaya-forwarded (0.0.3)
Installation
pip install --index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple/ --extra-index-url https://pypi.org/simple kaya-forwardedAbout 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:
- If the socket peer IP does not belong to any trusted CIDR (or there is no
peer address), the mixin leaves the context untouched —
clientremains the socket peer and all proxy headers are ignored. - Otherwise the client address is resolved from the headers, in order:
Forwarded(RFC 7239): thefor=entries are walked from right to left, skipping entries that are themselves trusted proxies (andunknown); 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:portin the selectedfor=value also populates the port.X-Forwarded-For: same right-to-left trusted-proxy walk; the port comes fromX-Forwarded-Portwhen present and valid.X-Forwarded-Host: first entry; port fromX-Forwarded-Portas above.
- 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.