feat: add per-IP rate limiting to login endpoint
Add a token-bucket rate limiter (golang.org/x/time/rate) that limits login attempts per client IP on POST /api/v1/login. Returns 429 Too Many Requests with a Retry-After header when the limit is exceeded. Configurable via LOGIN_RATE_LIMIT (requests/sec, default 1) and LOGIN_RATE_BURST (burst size, default 5). Stale per-IP entries are automatically cleaned up every 10 minutes. Only the login endpoint is rate-limited per sneak's instruction — session creation and registration use hashcash proof-of-work instead.
This commit is contained in:
24
README.md
24
README.md
@@ -2051,6 +2051,8 @@ directory is also loaded automatically via
|
||||
| `METRICS_USERNAME` | string | `""` | Basic auth username for `/metrics` endpoint. If empty, metrics endpoint is disabled. |
|
||||
| `METRICS_PASSWORD` | string | `""` | Basic auth password for `/metrics` endpoint |
|
||||
| `NEOIRC_HASHCASH_BITS` | int | `20` | Required hashcash proof-of-work difficulty (leading zero bits in SHA-256) for session creation. Set to `0` to disable. |
|
||||
| `LOGIN_RATE_LIMIT` | float | `1` | Allowed login attempts per second per IP address. |
|
||||
| `LOGIN_RATE_BURST` | int | `5` | Maximum burst of login attempts per IP before rate limiting kicks in. |
|
||||
| `MAINTENANCE_MODE` | bool | `false` | Maintenance mode flag (reserved) |
|
||||
|
||||
### Example `.env` file
|
||||
@@ -2455,6 +2457,28 @@ creating one session pays once and keeps their session.
|
||||
- **Language-agnostic**: SHA-256 is available in every programming language.
|
||||
The proof computation is trivially implementable in any client.
|
||||
|
||||
### Login Rate Limiting
|
||||
|
||||
The login endpoint (`POST /api/v1/login`) has per-IP rate limiting to prevent
|
||||
brute-force password attacks. This uses a token-bucket algorithm
|
||||
(`golang.org/x/time/rate`) with configurable rate and burst.
|
||||
|
||||
| Environment Variable | Default | Description |
|
||||
|---------------------|---------|-------------|
|
||||
| `LOGIN_RATE_LIMIT` | `1` | Allowed login attempts per second per IP |
|
||||
| `LOGIN_RATE_BURST` | `5` | Maximum burst of login attempts per IP |
|
||||
|
||||
When the limit is exceeded, the server returns **429 Too Many Requests** with a
|
||||
`Retry-After: 1` header. Stale per-IP entries are automatically cleaned up
|
||||
every 10 minutes.
|
||||
|
||||
**Why rate limits here but not on session creation?** Session creation is
|
||||
protected by hashcash proof-of-work (stateless, no IP tracking needed). Login
|
||||
involves bcrypt password verification against a registered account — a
|
||||
fundamentally different threat model where an attacker targets a specific
|
||||
account. Per-IP rate limiting is appropriate here because the cost of a wrong
|
||||
guess is borne by the server (bcrypt), not the client.
|
||||
|
||||
---
|
||||
|
||||
## Roadmap
|
||||
|
||||
Reference in New Issue
Block a user