Use ModSecurity Not A Plugin

When dealing with login attacks against wp-login.php and xmlrpc.php, consider using an application firewall such as ModSecurity rather than a WordPress plugin. Why? ModSecurity runs before the request hits PHP. Thus, WordPress is not even run on these known to be bad requests.

Some Numbers

Prior to enabling ModSecurity rules protecting wp-login.php and xmlrpc.php, these were the most popular files hit across all Weblogs.us WordPress installs. In December of 2016, wp-login.php was 23.48% of all hits, xmlrpc.php was 19.75%—A total of 43.23% all hits for what are really non-user facing pages. Similar behavior had been seen for the months prior as well.

After enabling ModSecurity rules punishing multiple bad login attempts for wp-login.php and xmlrpc.php, their total hits plummeted. In February, they accounted for only 3.78% of all hits. Did the robots go away? No, they were getting 403 errors, nearly 20% of hits resulted in a 403 error.

Caveat Emptor

Implementing successive failed login attack mitigation rules is quite easy on Apache. Rather than repeat how to do this, see Mika’s post WordPress login protection using ModSecurity. Unfortunately, Nginx is a different story. While ModSecurity is available for Nginx, any rule that requires a locationmatch parameter will not work (locationmatch is Apache specific). Instead, a custom location rule for wp-login.php and xmlrpc.php can be generated with ModSecurity enabled and the extra rules applied. It isn’t terribly elegant, but appears to work.

Ease of implementation aside, the performance benefits from blocking malicious login traffic earlier makes using a ModSecurity based implementation worthwhile. At Weblog.us, we dramatically cut down on resource usage by implementing ModSecurity rules for blocking malicious wp-login.php and xmlrpc.php accesses.

-John Havlik

[end of transmission, stay tuned]

10 Years Using WordPress

Ten years ago, this blog was created. Sure, I had written a few posts on another platform. However, it was ten years ago that I made my first post within WordPress (version 1.5 at the time). JD had just setup a WordPress install for me on Weblogs.us, and the post was a simple “This is my new blog” type post (no longer available).

Since then, I adopted and rewrote a plugin that is now approaching 2 Million downloads and an estimated 300k active users. By no means was this my first plugin, and it is not the last one I will create (something new will be arriving late this summer). While I had been playing with (x)HTML and CSS for years before WordPress even existed, I learned PHP through extending WordPress—some purists may cringe at the thought, but that is not my problem.

Additionally, I have had the opportunity to be a server administrator for Weblogs.us, starting back when we still ran Apache on Windows. Since that time, we’ve moved to Gentoo/Funtoo Linux VM guests on top of the hardware. And, in late May, we will begin migrating select Weblogs.us users to new Nginx+PHP-FPM setup running on top of some new hardware.

Lastly, I’ve attended 6 WordCamps, and have presented at 5 of them on 6 different topics in 8 sessions. This includes all 3 times WordCamp Minneapolis has been held, thus far. This year, I plan on attending more WordCamps than I’ve been able to in the past (really want to get to Austin and out to the West Coast). Not only are they a great excuse to see new cities, they are a great place to meet members of the WordPress community in person.

-John Havlik

[end of transmission, stay tuned]

mtekk.weblogs.us is now mtekk.us

No, the webhost did not change, I finally shelled out some cash for a domain name of my own. This in preparation of some future projects, and WordCamp MSP in November. More details on the projects will come later. In the mean time, feel free to start updating your links. Note that mtekk.weblogs.us will still link to the same blog for as long as it is hosted on weblogs.us (I do not have any intention of switching hosts any time soon).

-John Havlik

[end of transmission, stay tuned]

The Crib’s 5 Years Old

On this day, way back in 2005, the first post on this blog was published (there is one article that predates the blog, it was added after the first post and backdated). Since that time a lot has changed. WordPress has changed dramatically over the past five years. This blog originally ran WordPress 1.5; it now runs WordPress 3.0 beta 1.

Being the five year anniversary of the beginning of this blog, changing themes today seems appropriate. This is Cran-Berry 2. While it is a little rough around the edges, in the coming weeks it will be polished and expanded upon. Once WordPress 3.0 is released, a public version of Cran-Berry 2 will be available.

-John Havlik

[end of transmission, stay tuned]

Let’s Play a Game

Question: What causes the following error in Apache’s error logs?

[IP_address] Undeclared entity warning at line 226, column 1

Answer: A fairly popular, yet, poorly written WordPress plugin.

The first time this error hit the Weblogs.us error_log, one had no clue what was causing it. Unfortunately, the error does not indicate what file triggers the error. However, it will include the referring URI, if applicable. That’s how one found the specific virtual host on the Weblogs.us server that was triggering the error. Next, was finding the infringing code. To do this, one added define('WP_DEBUG', true); to the wp-config.php file for the virtual host. Now, there will be an avalanche of errors and warnings for most sites, all that needs to be done is sift through them and look for ones like “undeclared variable” and “undeclared index”.

Now, what was the actual culprit? The Twitter-for-Wordpress plugin. Specifically, lines 100, and 158. Line 100 tries to increment a non-initialized variable. To fix the issue on line 100, add a new line between line 66 and 67 and place in it $i = 0;. The error on line 158 is it tries to use the undeclared variable $username. What probably happened was author copied the line directly from line 53, while not properly modified for its location. Line 158 should read:
$messages = fetch_rss('http://twitter.com/statuses/user_timeline/'.$item['username'].'.rss');

After these two changes everything should be good to go. Yes, the plugin author was notified of these problems. We’ll see when they officially get fixed in the plugin.

-John Havlik

[end of transmission, stay tuned]