Rate limit login attempts per client address (closes #66) #143

Merged
clawbot merged 4 commits from issue-66-login-rate-limit into next 2026-09-29 01:03:38 +02:00
4 Commits
Author SHA1 Message Date
clawbot 194c0ded63 Count an IPv4-mapped login client by its IPv4 address (closes #66)
check / check (push) Successful in 2m33s
A proxy on a dual-stack listener forwards an IPv4 client as ::ffff:a.b.c.d,
whose /64 is the same for every IPv4 client, so one client's failed logins
refused everyone's. The rate limit key now unmaps the address first.

README.md now says that with the default trusted_proxies a client with a
private address can choose its counted address through X-Forwarded-For, and
that setting trusted_proxies to the proxy's own address closes this.

Model: opus-5-5
2026-09-28 22:49:07 +00:00
clawbot 39051ee4a3 Test that IPv4-mapped login clients are counted apart (closes #66)
check / check (push) Failing after 1m51s
Two IPv4 clients that the trusted proxy forwards in IPv4-mapped form must
not share one login count. Fails: both fall in the same /64.

Model: opus-5-5
2026-09-28 22:48:12 +00:00
clawbot e6c326fc96 Rate limit login attempts per client address (closes #66)
check / check (push) Successful in 3m3s
POST / had no limit, so the signing key could be guessed at no cost. It
is now limited to LoginAttemptsPerMinute (5) attempts per minute per
client by a new RateLimit middleware on github.com/go-chi/httprate. It
counts by the address the ClientIP middleware resolved through
trusted_proxies, an IPv6 client by its /64, and answers an attempt over
the limit with 429 and Retry-After. It runs after the body-size and CSRF
checks, so every attempt that reaches the key comparison is counted. The
image routes can reuse it. README states the limit; TODO narrows the
per-IP item to the image routes.

Model: opus-5-5
2026-09-28 21:22:25 +00:00
clawbot 1a50dd20d9 Test that login attempts are rate limited per client (closes #66)
check / check (push) Failing after 40s
The tests build the server's real routes and log in as a browser does.
The attempt after LoginAttemptsPerMinute failed logins from one client
must get 429 with Retry-After; another client must still get the login
form and log in with the signing key; two clients behind a trusted proxy
must be counted separately; X-Forwarded-For from an untrusted peer must
not get around the limit; an IPv6 client must be counted by its /64.

They do not compile yet: LoginAttemptsPerMinute comes with the change.

Model: opus-5-5
2026-09-28 21:11:42 +00:00