Expand description
Whose X-Forwarded-For to believe.
Behind a load balancer every request arrives from the balancer’s address,
so the client’s real address is only available in a header the balancer
added. The trap is that a header is something any client can send. A
server that reads X-Forwarded-For from whoever supplies it has not
learned the client’s address; it has let the client choose one. Anything
keyed on that address — a rate limiter, an audit log, a block list — is
then trivially defeated by a header.
So the header is believed only when the connection came from a proxy that was named in advance:
App::new()?.middleware(TrustProxies::from_config(app.config()))
// or
App::new()?.middleware(TrustProxies::at(["10.0.0.0/8", "172.16.0.0/12"]))Without this middleware, Request::ip is the address of whoever opened
the socket, which is always true even when it is not always useful. With
it, and only for a connection from a trusted proxy, it becomes the
left-most address in the forwarded chain that the trusted proxies did not
themselves add.
The same applies to the scheme. A proxy that terminates TLS forwards a
plain HTTP request with X-Forwarded-Proto: https, and without that
header an application would generate http:// links on a site that is
entirely https://.
TrustProxies::any() exists and is documented as what it is: correct on a
platform where nothing but the platform’s own proxy can reach the process
— a Heroku dyno, a Cloud Run container, a pod behind an ingress with no
other route in — and a hole anywhere else.
Structs§
- Forwarded
- What a trusted proxy told us about the original client.
- Trust
Proxies