Bot Protection
At a glance
Bot Protection wraps every public POST endpoint — auth, contract requests, newsletter, contact, feedback, club application — with a four-layer defence: a Cloudflare Turnstile widget that is invisible 95 percent of the time and GDPR-friendly, a server-side honeypot field that catches naive bots with a 422 response, an IP-based Redis rate-limit stack with dynamic thresholds per endpoint and structured audit with Prometheus counters that alert when traffic exceeds ten times the rolling baseline.
How it works
Layer one is Cloudflare Turnstile, embedded on every public POST endpoint that accepts unauthenticated input. The widget is invisible 95 percent of the time (challenge appears only on suspicious traffic), is GDPR-friendly (no cookie set), and the server validates the Turnstile token with a 5 second timeout. The validator is fail-open: if Cloudflare is unreachable within the timeout the request proceeds, so a Cloudflare outage cannot take the platform down — the other three layers absorb the risk.
Layer two is the honeypot field: a hidden HTML form field that human users never see (and therefore never fill), but naive bots fill in by default. Server-side validation rejects with 422 if the honeypot value is non-empty, which catches the simplest scrapers before they consume any business logic. Layer three is the rate-limit stack: an IP-based counter in Redis per endpoint with dynamic thresholds tuned to endpoint sensitivity (newsletter sign-up tolerates many requests per minute, club application is throttled hard).
Exceeding the threshold returns 429 with retry-after. Layer four is observability: every Turnstile failure, honeypot trigger and rate-limit block writes a structured log entry, increments a Prometheus counter and feeds an alert that fires on a spike (more than ten times the rolling baseline). The alert flows through the platform-operations alerting channel so the on-call operator knows when bot traffic is out of pattern.
Only POST endpoints are protected — GETs are public by design — and the protection is wired through middleware so individual endpoint authors do not have to remember to apply it.
Key capabilities
- Cloudflare Turnstile on all public POST endpoints, invisible 95 percent of the time and GDPR-friendly
- Fail-open Turnstile validation with 5 second timeout so Cloudflare outages do not break the platform
- Honeypot fields that catch naive bots with a 422 rejection before business logic runs
- IP-based Redis rate-limit counter per endpoint with dynamic thresholds tuned to sensitivity
- Structured audit log on every fail, trigger or block
- Prometheus counter with spike alert at more than ten times the rolling baseline
- Middleware-level integration so endpoint authors do not need to opt in
In practice
A scraping bot starts hitting the public newsletter sign-up at 40 requests per minute from a single IP. The honeypot field is filled by the bot's default form-fill heuristic; the server returns 422 within microseconds, no email is queued, the structured log records bot.honeypot.triggered and the Prometheus counter increments. Two minutes later the rate-limit threshold trips and the IP starts seeing 429 responses with retry-after.
Within a few minutes the spike alert fires (current rate is 40 times baseline) and the on-call operator confirms the block is holding. Meanwhile a real prospective member fills in the form on the same page, Turnstile passes invisibly in 200 ms, the request hits the newsletter endpoint and the welcome email is queued.
Features in this subsystem
4| ID | Status | Features |
|---|---|---|
| F08.14.01 | Shipped | Turnstile-widget — Cloudflare Turnstile på alla publika POST-endpoints (auth, contract-requests, newsletter, contact, feedback, klubbansökan); osynlig 95 % av tiden; GDPR-vänlig (ingen cookie); fail-open med 5 s timeout. ✅ PL-T072 |
| F08.14.02 | Shipped | Honeypot-fält — dolda formulärfält som botar fyller i; serverside-validering avvisar 422 om satta. Kompletterar Turnstile för enklaste botar. ✅ PL-T072 |
| F08.14.03 | Shipped | Rate-limit-stack — IP-baserad rate-limit per endpoint (Redis-counter); 429 efter tröskel; dynamiska gränser per endpoint-känslighet. ✅ PL-T072 |
| F08.14.04 | Shipped | Audit + alert — strukturerad logg på Turnstile-fail/honeypot-trigger/rate-limit-block; Prometheus-counter; alert vid spike (>10× baseline). ✅ PL-T072 |