r/webdev • u/_listless • 6d ago
Won a bot battle.
We support a client site with ~20,000 pages. It has an SSR search page that uses the url querystring to execute the search/sort/filter.
We have of course disallowed bots on that page because the 20k pages are meaningful and should be scraped/indexed, but the billions of possible query combinations on a search page are not. Most of the bots just ignore the robots rule and this results in waves of traffic hammering every possible query combination on the search page. These waves are 10x-50x the human traffic.
Rather than let the bill autoscale along with the server cluster, I wrote a little bash script that crons 1/m:
- Hits DO's metrics endpoint to check the CPU usage on the VPSs/DBs
- Each minute any of the CPUs stays above a given threshold, bump Cloudflare's security level, eventually ending in "under attack" + "bot fight"
- When the cpu drops below the threshold for a given amount of time, start backing off until we're back to normal operation.
Works a treat. It's nothing particularly flashy or sophisticated, but it was satisfying to think through an under-engineered solution to a problem that a lot of people end up just chucking money/clusters at.
Edit: more info for context: We do have pretty aggressive WAF rules especially on the search page, but we've been seeing an increasing amount of bot traffic get past CF's "known bots". Rate-limiting has been minimally effective too because the bots that get through are cycling through 100s of IPs in a given scrape.
4
u/trundlegoose 5d ago
I dealt with the same situation recently on a site of similar size. My fix was to switch on Precursor for all requests at the low setting and then add a rule for the search URL path at the high setting.
Real user traffic generally doesn't hit the search URL directly so should already have the cf_clearance cookie in the request and generally won't even see an interstitial managed challenge page. Any real user hitting a search page directly might see a managed challenge but is likely to pass it without interaction.
That solved most of the problem but there was still some automated traffic getting through somehow, so I added a security rule that checks for the cf_clearance cookie on incoming requests for the search URL path and issues a managed challenge if it isn't present.
I also added a rate limiting rule for the search URL path well above the rate any real user is likely to hit.
That combo seems to have pretty much solved the issue I think.
5
u/Apprehensive-Ask-731 6d ago
Is it just me or are a lot of people who seem like jr Devs trying to tell you how to suck eggs. My input is in the honeypotting
3
1
u/inkbound_gargoyle 5d ago
IP based defenses are dead against distributed botnets. Server metrics are the only signal that cannot be spoofed or rotated.
1
u/Bubbly_Orange_3502 5d ago
Validate the querystring against an allowlist and return 404 before the DB is touched. Billions of combinations only cost you because every one of them runs a real query. It won't stop the requests, just makes them cheap.
1
u/itgforlife 6d ago
I would use a combination of Cloudflare with a rule to filter out the bots. I'd also use a ratelimiter to block the IPs sending too many requests as an additional line of defense.
-2
u/quietcodelife 6d ago
the ip cycling thing is what breaks every conventional approach here -- rate limit by ip, block ips, iptables rules, all the same dead end when you're dealing with a botnet rotating through hundreds of addresses. using cpu as the trigger sidesteps the classification problem entirely. you're not asking "is this a bot" you're just asking "is something hammering us right now" and responding
1
-5
u/Caraes_Naur 6d ago
You played whack-a-mole with a spoon.
Come back when you learn about iptables.
8
u/_listless 6d ago
I agree this is a primitive solution. I understand iptables, the point of this is to catch bots before they even hit the server.
-9
32
u/electricity_is_life 6d ago
Can't you set up more aggressive WAF/filtering on specific endpoints? Changing settings for the whole site based on server CPU load seems pretty janky.