WordPress Security – Protect Against Malicious POST Requests with htaccess

.htaccessmod-rewriteWordpress

I've been looking at a log created by a WordPress plugin called Bad Behavior and in it there are many entries from different IP addresses at various intervals during the day that are requesting the following URL:

POST www.example.com/index.php?pubkey=b13bdb8297326599cf86aj25274e6a0c&bvTime=1549500166&bvVersion=0.1&bvMethod=getdata&sha1=true&sig=53fb643e40685ed89aa6754483b0a0d06bf1e63d0

The part of the URL that remains the same is /index.php?pubkey= then the rest is different for the other entries in the log.

What I am looking to do if it's possible, is to block those post requests via the .htaccess in the root directory.

While researching I found this answer here: Restrict Access To index.php – Apache

But since I don't really understand how to build directives correctly in the .htaccess file, I don't want to add something in there that can potentially block legitimate traffic or cause other problems.

Also while searching I found this piece of information at https://perishablepress.com/protect-post-requests/ but they warn you that using the following rule can be problematic if the website is not static and or uses forms, which this particular website does.

#deny all POST requests
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_METHOD} POST
RewriteRule .* - [F,L]
</IfModule>

So with that said, I hope enough information was added here that can help someone to help me find an answer to this particular problem.

Best Answer

The solution is indeed very similar to the question you linked to.

However, one question I would ask is, do you need to specifically target POST requests? Why not any request (GET or POST) that starts/index.php?pubkey=? Or does this carry some other meaning in WordPress?

In which case, you can do something like the following at the top of your .htaccess file:

RewriteCond %{QUERY_STRING} ^pubkey=
RewriteRule ^index\.php$ - [F]

No need for the <IfModule> wrapper. No need to repeat the RewriteEngine directive as that is no doubt set later in the file.


To specifically target POST requests then you can add another condition, as you did in your example:

RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{QUERY_STRING} ^pubkey=
RewriteRule ^index\.php$ - [F]

UPDATE: it didn't work as I was expecting, since I was able to load the page by visiting www.example.com/index.php?pubkey=

This could happen if the above directive is in the wrong place in the .htaccess file and is conflicting with other directives. It needs to be at the very top of the .htaccess file, before any existing mod_rewrite directives.

After some trial and error this is what blocked me completely, it works but I don't understand why, can you please explain the difference between what you gave me and this?

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{QUERY_STRING} (pubkey=.*) [NC]
RewriteRule (.*) - [F,L]
</IfModule>

This is far more general and blocks much more than just the URL stated in your question (possibly too much). These directives block any URL-path that contains pubkey= (case-insensitive) anywhere in the query string. So, it will block the following URLs (in addition to the URL stated above):

  • example.com/foo/bar?pubkey=xyz
  • example.com/foo/bar/baz?abc=1&xyz=2&pubkey=
  • example.com/foo/bar/baz?def=2&xyz=3&PuBkEy=xyz

These directives can be simplified:

RewriteCond %{QUERY_STRING} pubkey= [NC]
RewriteRule .* - [F]

No need to capture the RewriteRule pattern or CondPattern. The regex pubkey= is the same as pubkey=.*. The L flag is not required when the F flag is used. And as mentioned above, no need to repeat the RewriteEngine directive or use the <IfModule> wrapper.

Related Topic