2

How to Protect and Optimize your WordPress Installation

In this article I will explain some measures I took to protect my WordPress installation from attacks. More precisely, I will be talking about htaccess and what it can do for you. Besides that, I will also briefly explain some plugins. One of them is WP Super Cache, capable of optimizing your blog. If you use other methods, please comment.

Introduction

A few months ago my blog started having a load much higher than the usual, what made my server (JustHost, low cost…) block my account. Due to the high load, my blog started consuming too much resources and was blocked for two days. I tried to explain what was going on, but  they just reactivated my account after I took some measures to optimize WordPress. In the end I did this optimization and added a few things to protect my blog.

Before showing what I did, I want to share some statistics. First, the most viewed URL was not a page, but an image from the add-to-any plugin. The second in the list was wp-login.php.

Top URLs in hits

Top URLs in hits

Analyzing this numbers we could think the plugin is viewed more time because it was loaded more than once for each post (before and after the content), what would make it number 1 in number of hits. The problem is that other images like the social media links have aroung 1000 hits. It’s easy to realize that 400K is too much. The wp-login.php file is another issue, because 10K hits in a website that I’m the only one maintaining is also too much.

Next, some information about the top referrers. I’m not going to paste everything here, but among the top ones we have the following:

  • http://anime.blog.gogo.mn/
  • http://xac_2008.blog.gogo.mn/
  • http://more.blog.gogo.mn/
  • http://az.blog.gogo.mn/
  • http://nicebliss.blog.gogo.mn/

And so on… That’s a little bit strange isn’t it? That made Mongolia the top country viewing my blog. After a quick search I realized that this website is using my image from the add-to-any plugin. The developer of this blog added a CSS with a background pointing to my domain. I don’t know if it was on purpose or just an error when copying something from my site. Believing in the second option I got in touch with the developers about this.

Even though it could be just a mistake, the measures presented here are still valid.

.htaccess

The .htaccess file is used by Apache for rewrites, access control, etc. One of the basic things to do here is protect the wp-config.php. With a similar code we can block .htaccess itself.


# protect the htaccess file
<files .htaccess>
order allow,deny
deny from all
</files>

# protect wpconfig.php
<files wp-config.php>
order allow,deny
deny from all
</files>

Beside this simple modifications I also searched for more complete updates, which took me to 6G Firewall Beta. This article presents a collection of techniques to be used in the .htaccess that can help blocking malicious attacks. Many thins are going to depend on your WordPress installation, so I’ll show more or less how my implementation currently is (some explanations later):


ErrorDocument 403 /forbidden.html

# 6G BLACKLIST/FIREWALL (beta)
# @ http://perishablepress.com/6g-beta/

# 6G:[REQUEST STRINGS]
<ifModule mod_alias.c>
 RedirectMatch 403 /(\$|\*)/?$
 RedirectMatch 403 (?i)(<|>|:|;|\'|\s)
 RedirectMatch 403 (?i)([a-zA-Z0-9]{36})
 RedirectMatch 403 (?i)(https?|ftp|php)\:/
 RedirectMatch 403 (?i)(\"|\.|\_|\&|\&amp)$
 RedirectMatch 403 (?i)(\=\\\'|\=\\%27|/\\\'/?)\.
 RedirectMatch 403 (?i)/(author\-panel|submit\-articles)/?$
# RedirectMatch 403 (?i)/(([0-9]{5})|([0-9]{6}))\-([0-9]{10})\.(gif|jpg|png)
# RedirectMatch 403 (?i)(\,|//|\)\+|/\,/|\{0\}|\(/\(|\.\.|\+\+\+|\||\\\"\\\")
 RedirectMatch 403 (?i)/uploads/([0-9]+)/([0-9]+)/(cache|cached|wp-opt|wp-supercache)\.php
 RedirectMatch 403 (?i)\.(asp|bash|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf|well)
 RedirectMatch 403 (?i)/(^$|1|addlink|btn_hover|contact?|dkscsearch|dompdf|easyboard|ezooms|formvars|fotter|fpw|i|imagemanager|index1|install|iprober|legacy\-comments|join|js\-scraper|mapcms|mobiquo|phpinfo|phpspy|pingserver|playing|postgres|product|register|scraper|shell|signup|single\-default|t|sqlpatch|test|textboxes.css|thumb|timthumb|topper|tz|ucp_profile|visit|webring.docs|webshell|wp\-lenks|wp\-links|wp\-plugin|wp\-signup|wpcima|zboard|zzr)\.php
 RedirectMatch 403 (?i)/(\=|\$\&|\_mm|administrator|auth|bytest|cachedyou|cgi\-|cvs|config\.|crossdomain\.xml|dbscripts|e107|etc/passwd|function\.array\-rand|function\.parse\-url|livecalendar|localhost|makefile|muieblackcat|release\-notes|rnd|sitecore|tapatalk|wwwroot|add-to-any)
 RedirectMatch 403 (?i)(\$\(this\)\.attr|\&pws\=0|\&t\=|\&title\=|\%7BshopURL\%7Dimages|\_vti\_|\(null\)|$itemURL|ask/data/ask|com\_crop|document\)\.ready\(fu|echo.*kae|eval\(|fckeditor\.htm|function.parse|function\(\)|gifamp|hilton.ch|index.php\&amp\;quot|jfbswww|monstermmorpg|msnbot\.htm|netdefender/hui|phpMyAdmin/config|proc/self|skin/zero_vote|/spaw2?|text/javascript|this.options)
</ifModule>

# 6G:[QUERY STRINGS]
<IfModule mod_rewrite.c>
# RewriteCond %{REQUEST_URI} !^/$ [NC]
# RewriteCond %{QUERY_STRING} (mod|path|tag)= [NC,OR]
# RewriteCond %{QUERY_STRING} ([a-zA-Z0-9]{64}) [NC,OR]
# RewriteCond %{QUERY_STRING} (localhost|loopback|127\.0\.0\.1) [NC,OR]
# RewriteCond %{QUERY_STRING} (\?|\.\./|\.|\*|:|;|<|>|'|"|\)|\[|\]|=\\\'$|%0A|%0D|%22|%27|%3C|%3E|%00|%2e%2e) [NC,OR]
# RewriteCond %{QUERY_STRING} (benchmark|boot.ini|cast|declare|drop|echo.*kae|environ|etc/passwd|execute|input_file|insert|md5|mosconfig|scanner|select|set|union|update) [NC]
# RewriteRule .* - [F,L]
</IfModule>

# 6G:[USER AGENTS]
<ifModule mod_setenvif.c>
 #SetEnvIfNoCase User-Agent ^$ keep_out
 SetEnvIfNoCase User-Agent (<|>|'|&lt;|%0A|%0D|%27|%3C|%3E|%00|href\s) keep_out
 SetEnvIfNoCase User-Agent (archiver|binlar|casper|checkprivacy|clshttp|cmsworldmap|comodo|curl|diavol|dotbot|email|extract|feedfinder|flicky|grab|harvest|httrack|ia_archiver|jakarta|kmccrew|libwww|loader|miner|nikto|nutch|planetwork|purebot|pycurl|python|scan|skygrid|sucker|turnit|vikspider|wget|winhttp|youda|zmeu|zune) keep_out
 <limit GET POST PUT>
 Order Allow,Deny
 Allow from all
 Deny from env=keep_out
 </limit>
</ifModule>

# 6G:[REFERRERS]
<IfModule mod_rewrite.c>
# RewriteCond %{HTTP_REFERER} (<|>|'|%0A|%0D|%27|%3C|%3E|%00) [NC,OR]
# RewriteCond %{HTTP_REFERER} ([a-zA-Z0-9]{32}) [NC]
# RewriteRule .* - [F,L]
</IfModule>

# 6G:[BAD IPS]
<Limit GET POST PUT>
 Order Allow,Deny
 Allow from all
 # uncomment/edit/repeat next line to block IPs
# Deny from 195.225.145.17
</Limit>

First, I added a ErrorDocument pointing to an HTML created for this purpose. Next, I did some updates in the original code (commented lines using #). The updates in REQUEST_STRINGS and QUERY_STRINGS were done in order to keep WordPress working. Without those changes I was not able to access the admin area and, after managing to access it, I was not able to update the plugins.

I also commented the REFERRERS sections, because when someone searched in Google and tried to access access my site, got blocked. In the last section you can block IPs according to your needs. A good strategy is to use a plugin like Limit Login Attempts to detect failed attempts to log into your WordPress and later block the IPs in the .htaccess. Let’s move to the next part where I’ll explain these plugins.

Plugins

We will start with the Limit Login Attemps that I mentioned before.

Limit Login Attempts

This plugin logs the failed attempts of logging into your blog. You can set up the number of attempts before blocking the IP. You can define as well how long this lock will last, among other things. But the most important is that it keeps a log of the IP and the number of locks, allowing you to use this IPs to block those users using .htaccess.

PressBackup

This one is not exactly to protect your blog, at least now from external attacks. But it can save you a lot of headache is something bad happens to your WordPress. The idea is pretty obvious, keep the backup as up to date as possible, and in case you loose everything in your blog, you have a safe copy somewhere else that you can use to restore your site. Files and database can be saved with this plugin.

I use only the plugin, without an account in https://pressbackup.com/. If you want to pay a subscription you can have a professional backup solution.

This is the one I use, but there are alternatives:

Extra

There are other things you can do to protect your blog. Simple but efficient.

  • Change the $table_prefix in wp-config.php when you make a new installation.
  • Create another admin user besides the ‘admin’ for you to use and reduce the permissions of the ‘admin’ user to the minimum. This will allow attackers to continue trying to access the ‘admin’ and, in case they manage to do it, they won’t have permission to do anything. In my blog the great majority of lock outs from Limit Login Attempts is related to the ‘admin’ user, so I recommend that you do this.

Optimization

Let’s get to the second part of this post, the optimization of WordPress. One of the most efficient ways of optimizing web applications is using cache. You can avoid doing the same database queries in the database every time an user access your site. I recommend the plugin WP Super Cache.

WP Super Cache

This plugin has a long list of options to configure how the cache will work, but the more important is in the second tab: Advanced.

WP Super Cache Settings

WP Super Cache Settings

The most important things that you should select have a (Recommended) next to it. What matters most is in the beginning:

  • Cache hits to this website for quick access: this activates the cache.
  • Use mod_rewrite to serve cache files: the best method. Uses .htaccess to redirect into the cached pages. There could be problems which might require you to fix things yourself.
  • Use PHP to serve cache files: works pretty well and is very simple to set up. Nothing complex needed.
  • Legacy page caching: old method and not recommended. Only in case you can’t get the other two working.

After setting up, go to the Easy tab and click ‘Test Cache’. This way you can check if it is working or not.

Alternative:

References

6G Beta : Perishable Press
WordPress, Web Design, Code & Tutorials

Conclusion

Even if you don’t use your blog for work and you don’t get paid for what you write, it’s always a good idea to keep you property secure. Loosing all the content you produced is a waste of time, to say the least. If you use other methods or plugins, tell us in the comments.

Share Button

Oscar Dias

I work with software development since 2003 and I've used different programming languages. Currently I work with PHP in my own company Softerize.