Easy WordPress Security Measures


Barbed wire over WordPress logo
June 2013

Contents



Introduction


Recent (well, over a month ago now) widespread brute force attacks on popular blogging platforms including WordPress has renewed site owner interest in security measures. While these attacks are large in volume and scope, some very easy measures will defeat these attacks. While it's a good idea to address the imminent threat, realize these attacks are not sophisticated. Also consider more sophisticated attacks will happen a bit farther in the future. You must protect yourself from these as well. Better now when you have time to deliberate than later in the heat of actively repelling an attack.

Passwords


As always, your first line of defense is a strong password. This alone should be adequate to repel brute force attacks. Attackers use gigantic lists of common passwords. As long as yours is not on that list, you will be safe. I recommend at least 10 characters that include the typical mixed case, number and special characters, with no recognizable words in any language and unrelated to any personal data like birthdates, anniversaries, etc.

Besides a strong password, you should change it on a regular basis. Any password scheme that you can remember through regular changes is probably not strong enough. This means some sort of encrypted password management app is essential to good password security. KeePassXLink is to outside of this site is one example of such an app. For Windows users, I'm partial to security expert Bruce Schneier's Password SafeLink is to outside of this site, which uses his own very secure and efficient TwoFishLink is to outside of this site hashing algorithm. Recently, a Linux version in Beta testing has become available. These apps have tools that will generate good strong random passwords for you.

If long, completely random passwords rub you the wrong way, an easy alternative is using pass phrases. Phrases get their security from the sheer number of characters involved. There is no need for random strings. It's been shown that a long enough plain English pass phrase is just as difficult to crack as a good strong password, if not more so. For even extra security, throw in upper case letters, numbers and/or unusual characters into your phrase just as you might for a password. Inventing a phrase that involves a made up name is also a good measure, as well as a phrase that does not use proper grammar or word order. Like Yoda talk do! It must never be a phrase from literature, holy books, published songs, or movies. Like Yoda talk do, him do quote not. A phrase 20-30 characters in length is adequate. Be sure you can accurately type it without seeing what you typed. Unlike some passwords which many people need to hunt and peck to type, an easily touch typed phrase is almost impossible to be stolen by shoulder surfers.
to Contents

Usernames


In theory, your username is not a secret and no additional security should be expected by keeping it secret. Secret usernames fall into the "security by obscurity" category. Methods in this category should be considered very weak security measures. Good security practice means you assume anything you hide will be found. Focus on security that will work even when found, hiding alone is a false security.

Even though a secret username may be a false security, there is something to be gained in resisting the current brute force attack by simply not having a user named 'admin'. Apparently all recent brute force login attempts involve trying to login as 'admin'. With no user named 'admin', your site will be completely immune from this particular attack.

When installing WordPress, you should always select a different initial Administrator user than the default 'admin' user name suggested. If you've had your site for a while and did not do this, doing so now could make a mess of things as there is likely much content tied to your 'admin' user. There is no mechanism in the administration panels to change usernames. You must create a new user and delete the old one. Fortunately, when deleting the old account, you have the opportunity to assign content belonging to the old account to someone else, such as the new account you just created. There is also way to do an end run around the administration panels, without the need to reassign content. Access your database directly and find the 'admin' username in the users table using phpMyAdmin or a similar tool on your hosting control panel. The user ID is usually 1 and should be the first or near first entry. Simply change the user_login in the table to something else, save it, and you're done. While you're at it, you should change user_nicename too, it cannot be changed in the admin panels either. The admin panels only prevent you from changing the login name. Since the ID did not change, all content relationships remain, it's just that now the user ID is assigned a different user login name.
to Contents

Obfuscate "Wordpress"


I've noticed that since I started publishing this series of WordPress related articles, many hackers have attempted to hack into this apparently WordPress based site. (as well as attracting trackback spammers trying to spread their filth) As I mentioned in my first WordPress related article, this site is not WordPress based. Yet hackers try to hack my site and spammers try to spam it as if it were. Such idiots. Obviously, they are assuming that the mention of "WordPress" is typically an indication of a WordPress installation.

So another "security by obscurity" trick you may wish to implement is removing any reference to the keyword "WordPress" in your WordPress site. It will not prevent hackers from finding your site, but it might deter a few that find sites by keyword searches. As such, it's not much of a security measure, but it's easy to do and it may help a little. It's very difficult to obfuscate a WordPress installation enough to fool experts, but it's not too hard to fool keyword searches. However, the keyword "WordPress" appears in more places than you think, but still, removing the references is not too hard.

Footer. The default theme footer template contains the line "Proudly powered by WordPress" that appears at the bottom of every page. Obviously, one can simply remove this from the template, but I have clients who actually are proud to proclaim that they use WordPress and want legitimate users to know it. We can accomplish this proclamation and still hide from hacker and spammer searches because such searches are typically not very sophisticated. We can use techniques similar to the ones people use to hide email addresses on their sites in plain sight. One technique is to simply use HTML entities instead of plain text. Replace the link and text code line (line 17) in the footer template of the twentytwelve theme with this:
<a href="&#x68;t&#116;p&#58;&#x2f;&#47;&#119;&#111;r&#x64;p&#114;e&#115;s&#x2e;&#111;&#114;g&#47;" title="&#83;&#101;ma&#110;&#x74;&#x69;c &#80;er&#x73;o&#110;&#x61;l&#32;Publis&#x68;&#105;&#x6e;&#x67;&#32;&#x50;lat&#x66;or&#x6d;">&#x50;&#114;o&#x75;dly &#x70;&#x6f;&#x77;&#101;&#114;ed &#x62;&#x79; Wor&#100;&#80;r&#x65;&#115;&#115;</a>
The resulting link and text are exactly the same as the original. The random mix of plain text, hex and decimal codes will confuse virtually all keyword searches. (This version will not translate automatically like the original version though.) You could also use JavaScript or jQuery to really keep the keyword away from hackers. Scripting measures are beyond the scope of this article though. I will cover obfuscating email addresses with JavaScript in a future article, which of course could also be applied to obfuscating identifiable WordPress text.

Meta Widget. This widget also contains a link to wordpress.org. The easiest way to hide this link is to not use the widget, except that it's sort of a handy widget. You can obfuscate or remove the link in this widget by making a simple plugin that extends the WP_Widget_Meta class, replacing the widget() method with your version with the obfuscated or deleted link. Then simply register your widget class and use that instead of the Meta widget. Details on how to do this are too advanced to get into here, but PHP programmers will have little trouble doing this.

Links. There is yet another link to wordpress.org in the Links admin panel, which will show up on your pages if you use the Links widget. Either delete the link, do not use the Links widget, or configure the link category so it does not show up in the widget.

Generator Meta. This one could have slipped through the cracks. Every WordPress page has a generator meta tag in the head section of every HTML page indicating the current WordPress version. Add the following code to your theme's functions.php file to make this tag disappear completely.
function gm_no_version($gen, $type) {
    return '';
}
add_filter( 'the_generator', 'gm_no_version', 10, 2 );
/*tip: Always prefix function names with something unique to avoid name collisions,
       I use my initials. */
Post Content. You may want to mention WordPress in your blog posts, but doing so will again tip off hackers, just as it does for this site. There's an easy way to obfuscate this as well. Add the following shortcode handler to your plugin you started for generator meta. Then when you want the word "WordPress" to appear in your blog post content, type [ob-wp] instead of the actual word. The handler will output HTML entities representing the word instead of the actual text. To your end users, the word WordPress will appear as normal plain text.
function gm_obfuscate() {
    return '&#x57;&#111;&#x72;dP&#114;&#101;&#x73;&#115;';
}
add_shortcode('ob-wp', 'gm_obfuscate');
If you follow these steps, the keyword "WordPress" will not appear as plain text anywhere on your site, yet you can still proclaim your support of WordPress to all of your users.
to Contents

Limit Attempts


One real security measure is locking out users after a number of failed login attempts. I am surprised WordPress does not implement this out of the box. Fortunately, plugin developers have filled in the void, and there are a few options available. You should definitely implement this measure somehow. I personally use Limit Login AttemptsLink is to outside of this site, and am completely satisfied with it. It allows you to set your own parameters like number of allowed attempts and lockout time period. In addition, a user can be banned for a time period after a certain number of lockouts, and you can optionally have the system email you when a user has been locked out a number of times so you can take more drastic measures if required, such as blocking the IP address at the .htaccess level. It will also optionally log the IP and username of anyone locked out. Recommended.

I am not in any way suggesting other plugins that do something similar are inferior. I just have no experience with them. I encourage you to try out any that sound appealing and see which you like best. The only real take home message here is it is important to not let hackers hammer away at your login page 24/7 trying to guess your password. Once you decide on a plugin, do delete the unused plugins from your server. Neglected, unused plugins remaining on servers can become a security risk even if they are not activated.
to Contents

Limit Access


A very strong security measure is to limit access to the login file and/or the wp-admin folder contents. How strongly you can limit access will vary greatly by the nature of your site. If you have a large number of users from around the world, there may be little you can do. If you are the only user and you only access your site from one IP address, you can completely lock down your site so someone would have to physically hack onto your local internet connection to access your site. Solutions exist for situations between these extremes.

The basic strategy involves using .htaccessLink is to outside of this site directives to block or allow certain IP addresses access to certain folders and files, and/or password protecting access to certain folders and files. You cannot block access to the root folder nor /wp-content/ and /wp-includes/, otherwise regular not-logged-in users will not be able to view your site. Most people can limit access to /wp-admin/, unless their front end content uses AJAX techniques, in which case everyone needs to be able to access the file /wp-admin/admin-ajax.php. I'm comfortable simply limiting access to wp-login.php. Unless someone can forge a session cookie with a long random hexadecimal key, nothing can be done in /wp-admin/ without first going through wp-login.php. The following .htaccess script examples will be to only protect wp-login.php, but can be easily extended to protect /wp-admin/ as well if so desired. If your front end uses AJAX, it's possible to setup a rewrite rule set that allows access to that one file but nothing else in /wp-admin/.

If you are the only user accessing your site from one IP address, first determine what that is. Do note that most people's connection to the internet is via dynamic IP addressing, their IP address changes every time they connect. Your current IP address can be found through any number of online utilities, such as network-tools.comLink is to outside of this site (the number that 1st appears in the field above "Go!" is your IP). If you are behind a proxy or load balancer, you may not get your real IP address, but this is the one .htaccess will see too, so it all should work out. Add the following script above the WP segment of your .htaccess file in your WP installation folder. Be sure you use a plain text editor, not a word processor. Word processors will hopelessly mangle your file. Be sure to keep a copy of the unaltered file as a backup. When you're done editing and you've uploaded your modified file, do a test view of one of your pages. If you suddenly get a 500 server error, you've made a silly little typo somewhere on the file and the server is not happy about it. Find your error and fix it, or revert to your backup copy of the unaltered file.
<FilesMatch "wp-login\.php">
    Order Deny,Allow
    Deny from all
    Allow from 123.123.123.123
</FilesMatch>
Replace the 123.123.123.123 with your actual IP number. Upload to your server and now no one can have any hope of logging into your site unless they physically use your local internet connection. If you, like most people, are on dynamic addressing, you never know from day to day what your IP will be, and constantly changing the address in the .htaccess file is way too much of a hassle. All is not lost.

There is a notation called CIDRLink is to outside of this site that allows you to specify a range of IP addresses easily, though the notation itself is not intuitive. If you enter your IP address into robtex.comLink is to outside of this site, you can determine which block of IPs assigned to your ISP that it came from in CIDR notation. It looks something like 154.21.37.0/24. If you provide CIDR notation instead of a single IP address in the .htaccess script, anyone from any of the range covered will have access to your wp-login.php file. They still can't login to your site without a password, they can just load the page. The chance of someone using the same range as you being a hacker is very small, as hackers usually come from compromised servers which are typically assigned different IP ranges than ISP customers. Additionally, if you discover a hacker using your ISP to cause trouble, as an existing, paying customer, you should have no problem getting the hacker banned from your ISP service.

If you dig a bit into the robtex.com data, you'll likely see your ISP is actually assigned a large number of ranges. There is a chance you could be assigned an IP from a different range, so you may one day find your access blocked when this happens. Which ranges you could be assigned is likely limited to just a few out of the many available. The other ranges are designated for other purposes other than ISP customers, such as hosting. If you find yourself blocked by your own .htaccess script, determine your new address, determine the full IP range in CIDR format, then add a new Allow from line under the previous one with the new CIDR range. You shouldn't have to do this more than a few times before you discover all possible IP ranges you could possibly be assigned.

If you have many users from many ISPs, you cannot use this technique. If you notice the majority of your hack attempts are coming from certain countries or even certain hosting companies, you can reverse the allow from concept (including reversing the order line) and Deny from a list of known bad IP ranges. You can find lists of IPs assigned to certain problem countries like China and Ukraine. If you have no users from those counties, you can safely block them. Or if you have only a couple users from there, you could block all IPs from the country except for your users.

You can also use similar techniques to password protect the file or folder. This is very effective in blocking brute force attacks, but I feel entering two different passwords to enter my site just too cumbersome. You have two methods of password protection available in .htaccess, basic and digest. Of the two, digest is the more secure, but finding digest hashing utilitiesLink is to outside of this site if you don't have terminal access to your server can be difficult. Basic hashing utilities are readily available.

The recent brute force attacks have been so heavy that they could end up being a sort of Denial of ServiceLink is to outside of this site attack on your server. If so, IP blocking in .htaccess can be ineffective if you've developed a fancy 403 error page due to the processing required to serve this page. The best response then is to minimize the amount of processing needed to reject the requests to a bare minimum. To do so requires altering the file being requested, wp-login.php. This violates the recommendation from WordPress developers that core files never be modified. I believe in this special case modifying core files is acceptable as it is a temporary solution to an immediate threat. By the time an update is issued that overwrites the modification, it is hoped the modification is no longer required anyway.

To minimize the impact of brute force attacks, add the following script to wp-login.php just above the code line that begins "require( dirname(" at line 12. You cannot have any user in you system named "admin" or they will be locked out.
if(isset($_POST['log'])) {
    if('admin' == $_POST['log']) {
        header('HTTP/1.1 403 Forbidden');
        die('<html><head></head><body>HTTP/1.1 403 Forbidden</body></html>');
    }
}
to Contents

Referer (sic) Check


The correct spelling is "referrer" with 4 Rs, but when the HTTP header specification was written with a "Referer Field", no one noticed the error. Now, anything related to this field usually intentionally misspells the word for the sake of consistency. The referer field is sent by the user's browser as part of a HTTP request which indicates the URL of the document from which the current request originated. If you loaded the page http://example.com/index.html and on that page clicked a link to http://example.com/contact.php, the request for that contact.php page is sent to the example.com server with the HTTP_REFERER field set to http://example.com/index.html, the page from which the request originated.

So when the wp-login.php form submits a login request, one should expect the referer field to contain the wp-login.php URL. If not, something is fishy, and you can script .htaccess to reject any such requests. Thus you will see many security articles suggesting you do just that. Unfortunately, since the referer field is set by the user's browser, the data is easily spoofed. It is so easy, every single hack attempt I've reviewed had the correct value for the referer, despite there being no evidence of the form ever being requested in the first place. Apparently almost every hacker in the world has heard of this anti-hack tactic and takes measures to circumvent it. So I question whether this is an effective tactic. It will only stop the most stupid of hackers. It's easy enough to add this check, but it adds one more thing the server must do for every page load. Is it worth it? You'll have to decide for yourself. I don't think so.
to Contents

Online Editors


WordPress is SO easy! It even provides online editors so you can hack themes and plugins directly on your server without having to bother with moving files about via FTP. Awesome!

Except that there is no backup facility, so if you mess up your edit, you can easily lock yourself out of your own site. Further more, hackers can use this handy feature to do their own malicious hacking. The whole FTP thing doesn't look so bad after all, then you can use your favorite syntax highlighting programming editor as well. The online editors can be easily disabled by adding the following line to your wp-config.php file:
define('DISALLOW_FILE_EDIT', true);
Or you could add the filenames plugin-editor.php and theme-editor.php to the previously mentioned FilesMatch regexp (separate each filename with the bar (|) OR operator) so that they are just as restricted as your wp-login.php file, like so:
<FilesMatch "wp-login\.php|plugin-editor\.php|theme-editor\.php">
# more code follows...
This way, you can still use the editors, but anyone who's IP is not on the allow list cannot. What's the deal with the backslash before each dot? FilesMatch is a regexp statement, the string argument is a regular expression. In regexp, a dot means match any character. When we really want to match only a dot, we escape it with a backslash to indicate the dot be treated as a literal and not a regexp symbol.
to Contents

Stay Updated


Always keep the very latest version of WordPress installed. Security vulnerabilities are found all the time, keeping updated is the only way to stay ahead of the curve. This applies to themes and plugins as well. Be sure to sign up for any notification system offered by theme and plugin developers. Conversely, remove any themes or plugins you are not using from your server. You are much less likely to keep such files updated, and some vulnerabilities can be exploited even if the theme or plugin is not activated. Also do not leave old test installations and such on your server. Even if they are accessed from a subdomain, they are still part of the same server and can be exploited, affecting the live installation.

Keep Frequent Backups


If your site is hacked despite all your efforts, the only sure way to remove the hack is to wipe everything and restore from a known clean backup. You can't do this if you have no backups. Without backups, you may need to start over from scratch. All the content you generated in the past will be lost.
to Contents

Good Hygiene


That covers the easiest and most effective security measures you can do specific to WordPress, though some could be applied anywhere. There are more things you can do in Hardening WordPressLink is to outside of this site. Go ahead and do anything that appeals to you, but don't feel like you need to do everything. If you've done the above, you've likely done enough. Besides protecting your WordPress installation, you must also protect yourself and the computers you use to access WordPress. This means using good Internet hygiene for everything you do online. Do not install unfamiliar software unless it does something you really need and you've researched that it does what it says and nothing else. Do not open attachments in unsolicited email, nor follow any links. In fact, don't open suspicious emails at all. If you feel the need to follow a link, either re-type it or cut/paste it into a text editor before pasting into your browser's address bar. Never click on email links. Sign up for a free webmail account. Use this account for one time transactions where the risk of your address being distributed is high. Only provide your real email address to people and businesses you know and trust.

When installing software, watch out for piggybacked tool bars and other useless stuff you don't want or need that they try to slip in when you're not paying attention. Read each installation dialog carefully, never assume it's acceptable because it looks familiar. Read it!

Unless you're running Linux, use a quality anti-virus application. (Linux is not immune, but the damage that can be done is limited. Anti-virus is available if you're worried) Become familiar with your AV app's warning dialogs. There is usually a test file you can scan to trigger a warning. Assume any other such warnings are scams and ignore them. In fact, if anything sounds too good to be true, it's a scam, ignore it.

Make good use of a password manager. Use different passwords for each different site. Change all passwords for important sites on a regular basis. Do not use your computer's administrator account for day to day computer use. Create a lesser user for your day to day activities. The Windows UAC will prompt you for admin credentials when needed. This is annoying, but a good time to stop and think "Do I really need to do this?"

Keep all of your software updated. This does not mean you should pay for every upgrade, but you must install every security patch and service pack released for the software you have installed. If you can't be bothered to keep certain software current, it must not be important to you, in which case you should remove it. It could harbor unannounced security flaws.

Backup all your important data. Imagine a particular file disappeared tomorrow. Would this cause you any grief at all? If yes, back it up. If no, why are you keeping it? Delete it.

When you use FTP to move files, your FTP password is transmitted as plain text. If at all possible use SFTP or one of it's equally secure variants to encrypt your password so it cannot be sniffed out from dodgy networks. The popular FTP client FilezillaLink is to outside of this site provides a handy Site Manager that allows you to store access usernames and passwords so you can easily log into the FTP service. Unfortunately, Filezilla stores this information in plain text on your computer. Should anyone gain read level access to your hard disk, they can read your secret passwords. Always configure Site Manager to prompt you for a password during every connection. Store your passwords on an encrypted password manager, not Filezilla. It's a bit more work this way, but infinitely more secure.

Avoid connecting to any important site from a public computer, as they can have keyloggers or other data sniffers installed. Also avoid connecting to important sites even with your own computer if you are on a dodgy network like coffee shop and motel wi-fi networks. Only do so if you have established a secure https: connection from your own computer. If you must use a dodgy network to access an important site, change the password at the end of every session until you are able to change the password one last time from a secure network.

Ultimately, once you've installed basic security measures, your best protection is your own instinct. Pay attention to what you are doing. Resist falling into auto-pilot mode. If anything seems the least bit wrong, do not doubt your instinct, instead, investigate. Never accept anything that smells funny until you've assured yourself through investigation that it actually is all right. Enjoy your WordPress site, but be safe! to Contents

«Back

Comments, feedback, and questions are always welcome. Email me at Javascript must be enabled.