Cloudflare Bot Fight and WAF, how to cut malicious bots off the store
Opselis
Bot score, JS challenge and rate limit in Cloudflare. Why the edge sits in front of origin, how bot scoring works and how to set rules on login, cart and API without blocking the payment webhook.
Cloudflare Bot Fight (and Super Bot Fight on paid plans) scores whether a request is a human, a verified bot or automation. WAF and Rate limiting cut paths before traffic reaches PHP and the database. The tool sits at the edge: the domain DNS points at Cloudflare, TLS ends there, origin has only an address from the Cloudflare IP list or a tunnel. A malicious bot is stuffing on login, catalogue scraping, carding on payment, recon on /xmlrpc.php and GraphQL. In the application log you see 401 and 429. On the host you see busy workers.
What it is for
You use it when the store or API gets a mass of GET and POST that do not buy. The edge takes load off origin. Verified bots (Googlebot, monitoring) stay on allow. The rest with a low bot score (below the threshold, usually 30) get a Managed Challenge or Block. Rate limit on /customer/account/login, /wp-login.php, search and cart. The payment webhook (path and gateway User-Agent) must be an exception, or the order is lost.
How it works
Each request gets a bot score from 1 to 99. A low score: automation. JA3, JS behaviour, ASN, IP history. Security Analytics shows sampled logs: path, score, action (allow, challenge, block). A WAF custom rule: an expression (uri.path, cf.bot_management.score, ip.geoip.asnum) and an action. Origin without a public A/AAAA: Cloudflare only or Wireguard. Then a port scan from the internet does not hit PHP.
How to set it up
In Cloudflare, store domain: SSL/TLS, Full (strict), origin certificate. Security, Settings, Security Level medium. Security, Bots: enable Bot Fight Mode. On Pro and above: Super Bot Fight, Definitely automated: Block, Likely automated: Managed Challenge, Verified bots: Allow.
Security, WAF, Custom rules. Login rule: (http.request.uri.path contains "/customer/account/login" or http.request.uri.path contains "/wp-login.php") and cf.bot_management.score lt 30 → Managed Challenge. API rule: catalogue GraphQL and REST, score lt 20 → Block. Rate limiting: 10 requests per minute per IP on the login path. Exception: payment webhook uri.path Skip (Stripe/PayU/Przelewy24).
Security, Analytics: 24 h, Bot filter. If the challenge catches customers behind a corporate proxy, narrow to the path, not the whole hostname. Origin: host firewall, 443 only from Cloudflare IPs (the list Cloudflare publishes). Layer description: security.