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.
KeePassX
is one example of such an app. For Windows users, I'm partial to security expert Bruce Schneier's
Password Safe,
which uses his own very secure and efficient
TwoFish
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:
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 'WordPress';
}
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 Attempts,
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
.htaccess
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.com
(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
CIDR
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.com,
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 utilities
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 Service
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.
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 FilesMatchregexp
(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 WordPress.
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
Filezilla
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