Promote the 2026-08-30 review security fixes and supplies ordering to main
This commit is contained in:
@@ -6,6 +6,23 @@ every connection - so it must be stripped before the value is stored (audit),
|
||||
matched (dashboard IP fallback), or used as a rate-limit key (login). Left in,
|
||||
it makes every request look like a different client.
|
||||
|
||||
X-Forwarded-For is NOT read here. A client can send that header itself, so
|
||||
trusting it unconditionally hands any caller a free identity: the login rate
|
||||
limit and the account lockout are keyed on this value, and the audit log
|
||||
records it. Reading it directly also walked around TRUSTED_PROXY_COUNT, which
|
||||
exists precisely to decide whether a proxy is really in front (see the ProxyFix
|
||||
block in shopdb/__init__.py).
|
||||
|
||||
The trusted case is already handled upstream. When TRUSTED_PROXY_COUNT is set,
|
||||
ProxyFix resolves X-Forwarded-For into remote_addr before the request reaches a
|
||||
view, so remote_addr is the real client. When it is unset, remote_addr is the
|
||||
peer that actually connected. Either way remote_addr is the trustworthy source,
|
||||
which is why this module only strips the port from it.
|
||||
|
||||
A site behind IIS or nginx MUST set TRUSTED_PROXY_COUNT (1 for a single proxy),
|
||||
or every request will key on the proxy's own address and the per-client rate
|
||||
limit becomes one shared bucket.
|
||||
|
||||
Port stripping is IPv6-aware: a bracketed [2001:db8::1]:443 loses its port; a
|
||||
bare 2001:db8::1 (many colons, no brackets) is returned untouched.
|
||||
"""
|
||||
@@ -26,14 +43,11 @@ def strip_port(ipaddress):
|
||||
|
||||
|
||||
def client_ip(request_obj):
|
||||
"""First-hop client IP behind one proxy, port stripped.
|
||||
"""Client IP, port stripped, from the connecting peer.
|
||||
|
||||
Honors the first X-Forwarded-For hop, else remote_addr. Returns None only
|
||||
when neither is present (callers that need a non-null key coerce it).
|
||||
Resolved from remote_addr, which ProxyFix has already rewritten from
|
||||
X-Forwarded-For when TRUSTED_PROXY_COUNT says a proxy is really in front.
|
||||
Returns None only when remote_addr is absent (callers that need a non-null
|
||||
key coerce it).
|
||||
"""
|
||||
forwarded = request_obj.headers.get('X-Forwarded-For')
|
||||
if forwarded:
|
||||
raw = forwarded.split(',')[0].strip()
|
||||
else:
|
||||
raw = request_obj.remote_addr
|
||||
return strip_port(raw)
|
||||
return strip_port(request_obj.remote_addr)
|
||||
|
||||
Reference in New Issue
Block a user