Back to Posts

Limiting POST requests to WordPress with Hiawatha

Ali Kuru in Linux, Software, Web, wordpress, hiawatha

With being used by more than 25 percent of all websites, WordPress is by far the most popular CMS today. This much attention also makes it quite popular among the hackers and script kiddies, which usually rely on automated bots to check vulnerabilities and exploit them. And when successful, enslaved sites generally controlled with commands sent via POST requests.

It's best if you can keep your WordPress core, theme and plugins always up to date, but sometimes this can be problematic with a fairly old instance that can't be upgraded because of an orphaned piece in the setup. Most secure option for such a site would be going static. If that's not applicable because of a function that requires interaction, locking unnecessary features on the webserver level might help ease the pain.

I use Hiawatha for these kinds of legacy WordPress sites. It is an open source webserver with a focus on security; has built-in SQLi, XSS and CSRF/XSRF protection and quite easy to setup. If you are not familiar with Hiawatha, I suggest you to check out the official manual and how-to pages. You can find a step by step guide for a secure Hiawatha installation here.

Creating a chain reaction with URL toolkit

Hiawatha's URL toolkit is where you can perform actions based on the URL or on the URL itself. It is usually used for creating rewrite rules but actually more powerful than that. Using regular expressions, you can match a pattern and redirect it, limit/deny access to it or forward it to a different CGI handler.

It also allows you to perform actions based on request headers of the client, which I use in my solution;

UrlToolkit {
		ToolkitID = allowpost
		Match ^/profile/$ Return
		Header X-Dress-Code black-tie Return
		Method POST DenyAccess
}

VirtualHost {
		Hostname = www.legacysite.tld
		...
		UseToolkit = allowpost
		...
}

What's happening here is we first check with allowpost toolkit whether the user is browsing the /profile/ page, where everyone allowed to POST in our hypothetical setup. If he is, we tell Hiawatha to ignore the rest of the toolkit and carry on. If he is not, Hiawatha will refer to the next line and check his request headers.

In this case, we have defined a custom request header X-Dress-Code and black-tie as the key. So, as long as user is sending our server this header-key pair, Hiawatha again will ignore the rest of the toolkit and the user will be allowed to POST.

Last line of the allowpost toolkit, where user will end up if he's not viewing his profile or not dressed correctly, is self-explanatory. He will be denied of making POST requests.

Dressing up for a formal visit

As you can easily guess, the X-Dress-Code is a totally imaginary header created by me for adding some fun to this boring tutorial :) You can use one of the official headers listed here or define yourself a new one. I suggest you create a custom header for distinguishing your authorized users.

If you opt to tailor your own custom header, you'll need a plugin to pass that to your server. Modify Header Value plugin for Chrome and Firefox can handle this task for you. Here is a sample configuration, click for a bigger version:

Modify Header Value plugin for Firefox and Chrome

Final thoughts

If you are seeing unusual POST requests in your logs and especially those requests are being made to weirdly named PHP files located in places not common for a WordPress installation, your site is probably already compromised.

If somehow you are unable to upgrade your setup, again, it's best if you convert the whole site to a static one and limit CGI execution altogether. Unless that's not really an option, then you might start tinkering with the POST requests. It might let you breath while you clean up things and add further protection for not getting compromised again.

Although it's possible to limit POST requests in different ways with other web servers like Apache and Nginx, I recommend you to use Hiawatha for added security. The solution I offer here involves several checks, so it might hinder your performance a bit, particularly if you are getting a considerable amount of traffic. However, since Hiawatha is also a serious contender in performance, I don't believe it will lag behind of others with similar configurations. Nevertheless, your mileage may vary.

Update: A previous version of this post offered a rather long and complicated solution for the problem at hand. Thanks to Hugo Leisink, the creator and main developer of the Hiawatha, we now have a simpler config.

PhD in Microbiology, head of digital at Kapital Media. Interested in geekery, gadgets and ever-evolving web.

Read Next

Running Node.js on Wheezy