I run a WordPress server. WordPress being WordPress, I get several hundred IPs per day attempting to brute force logins. I have a fail2ban script which adds these IPs to an IP list which is blocked in the CloudFlare firewall. Right now I have it just set to block IPs flagged by fail2ban for an hour. This works pretty well, but I’m curious about effects on IP reputation and the like. If I set it to browser challenge mode and the bot fails, which it will, does that continue to block queries from that IP until a challenge is passed, or will it be allowed back unchallenged after the fail2ban rule expires[1]? Does getting blocked or failing a browser challenge affect the IP’s reputation or behaviour for other CloudFlare sites? (Anything which is trying to brute force my login will be doing it to other sites as well - it would be nice if I could hint to CF it’s a bad IP, for example.)
[1] Obviously I can set fail2ban’s timeout higher, but there are tradeoffs here with recycled and shared IPs.
The proper approach to this is with 2FA pages with CF Teams or lock down the path to your business/personal VPN.
Fail2ban consumes a lot of resources that you could free yourself of in this case.
This is not a business site and we have a couple of dozen users with accounts and a budget of approximately “whatever we find behind the sofa”, so I can’t enforce a VPN or any other similar features. I have 2FA on the server side, so I’m not concerned about anybody gaining access to my site with a lame password guessing bot, just resource consumption. A concerted password guessing attempt burns more CPU resources than the entire legitimate usage of the site by about an order of magnitude and can last hours, and we get several of those per day. fail2ban uses a vanishing amount of resources by comparison (I don’t have it parsing my general access logs, just interesting pre-filtered ones).
As @jnperamo suggested, Access (Teams) can lock this down pretty easily, and it’s free for up to 50 users. My setup is below. Known IP addresses aren’t challenged (you can add a ton of them), and for those not at a known IP address, known email addresses are emailed a login token that sets a cookie for up to a month.
Had a bit of a look through the docs for Access, and it looks like an interesting option - I’ll look into it further. One thing that does occur though is that it can’t protect against abuse of stuff like xmlrpc and the REST API endpoints, which do need to be available publicly but are regularly attacked by the same bots that target the login page, whereas my fail2ban config gets those as well.
Does your site need to be public and accessible via Google etc?
If not why not use Zone Lockdown on the domain in question and restrict access to your users IPs only?
It’s a public blog. Writers with accounts are scattered across home, business and mobile network connections worldwide - IP whitelisting is definitely not a reasonable option. The CF Teams SSO-based access control suggested by others is a bit more realistic.
Do you even need xmlrpc? I block that one with Firewall Rules, as I don’t do any type of remote/app admin of the site.
I also use Wordfence which does a pretty good job of blocking what does get through Cloudflare. I then look at “Live Traffic” in Wordfence to add more restrictions to my Firewall Rule.
To my continuing annoyance, Jetpack still hits xmlrpc so I can’t entirely turn it off. WordFence is pretty good, but it’s still a PHP invocation which is expensive even with their optimisation, so I’d rather avoid if possible.
Looks like Jetpack do publish their IP ranges (here, if anybody else is looking at this: Hosting Reference Documentation), though they advise against using them for some reason.
We ban IP addresses for 24 hours, for a variety of reasons.
However, when it comes to the WordPress login, we have simply changed the login URL. I realise this is security by obscurity, but it seems to be the most effective way of stopping automated bots without whitelisting IP addresses and such like. We then set our webserver to deny all requests to wp-login.php and xmlrpc.php