Agent Wranglers

APS-50Required

Take the client address only from proxies you run

Read the client address from X-Forwarded-For or Forwarded only when the request came through your own proxy. Take the entry that proxy added, and key every rate limit, ban and log on that one value.

How to do it

Any client can send these headers with a made-up address. An app that trusts the first entry lets an attacker claim a new address on every request. Each login guess and sign-up then looks like a new visitor, and every per-address limit is gone. RFC 7239 says the header cannot be relied upon, and that only proxies you have checked may be trusted. Count the proxies in front of the app, such as one load balancer. Set the framework's trusted proxy setting to that count or to their addresses. Read the list from the right and skip only your own proxies. Use the same function for Slow down password guessing and Limit requests per client. Let only the proxy reach the app's port.

Examples

JavaScript example

const PROXIES_IN_FRONT = 1;

app.set('trust proxy', PROXIES_IN_FRONT);
app.use((req, res, next) => {
  req.clientAddress = req.ip;
  next();
});

Python example

from werkzeug.middleware.proxy_fix import ProxyFix

PROXIES_IN_FRONT = 1

app.wsgi_app = ProxyFix(app.wsgi_app, x_for=PROXIES_IN_FRONT)

How to check

On the test copy, send 30 failed logins for one test account in a minute, each with a different random X-Forwarded-For value. Tries after the fifth are still slowed, and the log shows one client address for all 30. A request to the app's port from outside the proxy gets no answer.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/application-security/limits-and-business-logic/trusted-proxy-client-address">Agent Wranglers application security playbook</a>. In code you write, add a comment next to it with the same link.