Rule 1: Allow Good Bots | Rule 2: Block Potentially Malicious Requests | Rule 3: Block Bad Bots | Rule 4: JS Challenge
The order of the next three rules is less important. It makes a difference in terms of logging – if a bot is blocked by rule 2 it won’t be logged by rule 3 – but not in effectiveness. Rule 2 blocks potentially malicious requests, whether they originate from bad bots or humans. This is a long rule set, so I’ll break it down.
I want to block …
1. Malicious Login Requests. These are very common, usually from bots. Bad bots hammer on WP login pages all day every day using dictionary attacks attempting to log in. Many WP experts call this ‘normal’ and advise ignoring it. Nope. I refuse to accept my site being constantly under malicious attack as somehow ‘normal’. I obfuscate my login url using the plugin WPS Hide Login, so I can block these nefarious fiends at the CF reverse proxy, before they get to my site or even my server. The “/css” piece allows my obfuscated login page to be properly formatted.
(http.request.uri.path contains "/wp-login.php") or
(http.request.uri.path contains "/login" and not http.request.uri.path contains "/css")
2. DOS and Other Mischief. XML-RPC enables me to write and publish content offline, for example in Microsoft Word. I never do that. XML-RPC is also used by JetPack and certain other WP plugins and remote apps. I don’t use those either. Since I am not using it, XML-RPC is just another attack vector for bad bots to hammer on. No thanks, I’ll block it instead.
(http.request.uri.path contains "/xmlrpc.php")
3. User Enumeration. User Enumeration allows bad bots to harvest user names, a step closer to malicious login. The good people at WP have their collective head stuck deep in the sand on this one, stating categorically that “usernames and user ids are not private or secure information”. OK, then why then does my log show *lots* of frequent user enumeration attempts by bad bots? Silence.
(http.request.full_uri contains "?author")
4. Sensitive WP Files. wp-config.php holds the keys to the castle – extremely sensitive information like my database access credentials. Other files with sensitive information include htaccess, htpassword, my error log, and WP and Duplicator installation files. My host blocks at least some of these, so these rules are at least partly redundant, but for critical security items redundancy is fine with me.
(http.request.uri.path contains "/wp-config.php") or
(http.request.uri.path contains "/.htaccess") or
(http.request.uri.path contains "/.htpasswd") or
(http.request.uri.path contains "/install.php") or
(http.request.uri.path contains "/setup-config.php") or
(http.request.uri.path contains "/installer.php") or
(http.request.uri.path contains "/installer-log.txt") or
(http.request.uri.path contains "/installer-data.sql") or
(http.request.uri.path contains "/database.sql")
5. Nuisance File Requests. These file requests may seem harmless. Either the files are benign or non-existent on my site. But that doesn’t stop bots from repeatedly requesting them. Benign files like readme.html are none of bots’ damn business, and I don’t need floods of requests for non-existent files using up my bandwidth generating 404 not found pages.
(http.request.uri.path contains "/readme.html") or
(http.request.uri.path contains "/readme.txt") or
(http.request.uri.path contains "/license.txt") or
(http.request.uri.path contains "/wpad.dat") or
(http.request.uri.path contains ".php.suspected") or
(http.request.uri.path contains "/.git") or
(http.request.uri.path contains "apple-app-site-association") or
(http.request.uri.path contains "autodiscover.xml") or
(http.request.uri.path contains "assetlinks.json") or
(http.request.uri.path contains "dnt-policy.txt")
5. TOR. I’ve gone back and forth on this. I wish I could accommodate legitimate privacy enthusiasts – with whom I sympathize and somewhat identify. But about 95% of TOR traffic is demonstrably malicious. Blocked.
(ip.geoip.country eq "T1")
6. Direct Acccess to CPanel and WHM. As far as I know I invented this. I don’t know of anyone else doing it. My web host and others told me it couldn’t be done. Yea me! I was troubled by the seeming security weakness of direct access to my CPanel and WHM accounts. I could fret like a terrified school girl over the security of my WP admin account, but if a bad guy, gal, or non-binary hacks my CPanel – game over. So, I block direct access and log in through my relatively well-protected hosting account.
(http.request.uri.path contains "/cpanel") or
(http.request.uri.path contains "/whm") or
(http.request.full_uri contains ":2082") or
(http.request.full_uri contains ":2083") or
(http.request.full_uri contains ":2086") or
(http.request.full_uri contains ":2087")
7. wp-admin Folder. There is a much better way to block access to my wp-admin folder using my IP address. But I like being able to do admin work from home or work or a random coffee shop (yes that last is a bad practice, and yes I it do anyway, but always over https). Best I can do, as far as I know, is to block non-U.S. access – since I never travel outside the U.S. I also have to exempt /admin-ajax.php due to unfortunate decisions by the WP People in Charge.
(ip.geoip.country ne "US" and http.request.uri.path contains "/wp-admin" and not http.request.uri.path contains "/admin-ajax.php")
8. Zero-Day Exploits. Suppose in spite of my precautions a hacker is able to plant malware on my site. One thing that he/she/xe might do is upload malicious php files then execute them. A frequent hacker target for uploading malicious files is /wp-content/uploads, so …
(http.request.uri.path contains "/wp-content" and http.request.uri.path contains "/uploads" and http.request.uri.path contains ".php")
That’s it. Here’s the full set for Rule 2 …
(http.request.uri.path contains "/wp-login.php") or
(http.request.uri.path contains "/login" and not http.request.uri.path contains "/css") or
(http.request.uri.path contains "/xmlrpc.php") or
(http.request.full_uri contains "?author") or
(http.equest.uri.path contains "/wp-config.php") or
(http.request.uri.path contains "/.htaccess") or
(http.request.uri.path contains ".htpasswd") or
(http.request.uri.path contains "/install.php") or
(http.request.uri.path contains "/setup-config.php") o
(http.request.uri.path contains "error_log") or
(http.request.uri.path contains "/installer.php") or
(http.request.uri.path contains "/installer-log.txt") or
(http.request.uri.path contains "/installer-data.sql") or
(http.request.uri.path contains "/database.sql") or
(http.request.uri.path contains "/readme.html") or
(http.request.uri.path contains "/readme.txt") or
(http.request.uri.path contains "/license.txt") or
(http.request.uri.path contains "/wpad.dat") or
(http.request.uri.path contains ".php.suspected") or
(http.request.uri.path contains "wppov.com/.git") or
(http.request.uri.path contains "apple-app-site-association") or
(http.request.uri.path contains "autodiscover.xml") or
(http.request.uri.path contains "assetlinks.json") or
(http.request.uri.path contains "dnt-policy.txt") or
(ip.geoip.country eq "T1") or
http.request.uri.path contains "/cpanel") or
(http.request.uri.path contains "/whm") or
(http.request.full_uri contains ":2082") or
(http.request.full_uri contains ":2083") or
(http.request.full_uri contains ":2086") or
(http.request.full_uri contains ":2087") or
(ip.geoip.country ne "US" and http.request.uri.path contains "/wp-admin" and not http.request.uri.path contains "/admin-ajax.php") or
(http.request.uri.path contains "/wp-content" and http.request.uri.path contains "/uploads" and http.request.uri.path contains ".php")
Then: Block

