dave2wave commented on issue #535:
URL:
https://github.com/apache/tooling-trusted-releases/issues/535#issuecomment-3781153905
Good — this is a solid Apache base. For **rate limiting + ProxyFix**, there
is really only **one critical gap** in what you’ve shown, plus a couple of
tightening recommendations.
I’ll focus *only* on what affects **client IP correctness and rate
limiting**.
---
## The critical issue (this matters)
### ❌ You are NOT forwarding the client IP
You **do not set `X-Forwarded-For`** anywhere.
That means:
* Hypercorn sees Apache’s IP as the client
* `request.remote_addr` will always be the proxy
* **All clients share one rate limit**
* ProxyFix cannot help if the header is missing
---
## The one required fix
### ✅ Add `X-Forwarded-For` (append, not overwrite)
Add this **exactly**:
```apache
RequestHeader add X-Forwarded-For "%{REMOTE_ADDR}s"
```
### Why `add` and not `set`
* `add` **appends** to any existing chain
* `set` overwrites and breaks multi-hop semantics
* ProxyFix expects a proper chain
---
## Final minimal header block for rate limiting
```apache
# Preserve original host
ProxyPreserveHost On
# Forward client connection info
RequestHeader add X-Forwarded-For "%{REMOTE_ADDR}s"
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
```
This is the **minimum required** for correct rate limiting.
---
## How this lines up with ProxyFix
With this Apache config:
```apache
RequestHeader add X-Forwarded-For "%{REMOTE_ADDR}s"
```
And this Quart config:
```python
app.asgi_app = ProxyFix(
app.asgi_app,
x_for=1,
x_proto=1,
x_host=1,
)
```
You get:
| Value | Result |
| --------------------- | --------------------------- |
| `request.remote_addr` | **real client IP** |
| Rate limiter key | Correct |
| Header spoofing | Prevented |
| Dev mode | Safe when ProxyFix disabled |
---
## What NOT to add (important)
❌ **Do not** do this in Quart:
```python
request.headers["X-Forwarded-For"]
```
❌ **Do not** trust more hops than you have:
```python
x_for=2 # wrong unless you truly have 2 proxies
```
❌ **Do not** enable ProxyFix in dev
---
## Verify in 30 seconds
### Temporary Quart endpoint
```python
@app.get("/_debug/ip")
async def debug_ip():
return {
"remote_addr": request.remote_addr,
"access_route": request.access_route,
}
```
### Expected result in prod
```json
{
"remote_addr": "203.0.113.42",
"access_route": ["203.0.113.42", "127.0.0.1"]
}
```
If `remote_addr` is `127.0.0.1`, rate limiting is broken.
---
## Slowloris settings (sanity check)
These **do not interfere** with rate limiting:
```apache
RequestReadTimeout header=20-40,MinRate=500 body=60,MinRate=300
ProxyTimeout 300
```
They operate **before** headers are forwarded.
---
## Summary (rate limiting + ProxyFix only)
✔ Apache config is mostly correct
❌ Missing `X-Forwarded-For`
✔ Add exactly one header line
✔ ProxyFix with `x_for=1`
✔ Rate limiter will now work per client IP
If you want, next we can:
* Add **dual-key rate limiting** (IP + user)
* Add **trusted proxy CIDR validation**
* Verify behavior under HTTP/2 concurrency
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]