Securing Your WordPress Website

Advertisement

Security has become a foremost concern on the Web in the past few years. Hackers have always been around, but with the increase in computer literacy and the ease of access to virtually any data, the problem has increased exponentially. It is now rare for a new website to not get comment spam within days of its release, even if it is not promoted at all.

securityimage1

This increase in naughty behavior, however, has spurred developers to write better code, and framework vendors have implemented many functions to help coders in their battle against the dark side.

Because data validation and sanitization is a big part of both security safeguards and normal user-input processing, by securing our code we will be not only protecting our behinds, but offering a better, more solid user experience.

While a large part of this article is specific to WordPress, a sizeable chunk is about general practices that anyone can use. Even the WordPress-centric sections contain useful logic, so reading them may well be worth it even if you use a different framework.

URL-Based Exploits

With URL-based exploits, hackers try to find weak spots on your website by making requests that would normally return an error but for some reason are completed.

http://mysite.com/trying/to/exploit/%2F/config

The above hypothetical URL is essentially a stab in the dark by a hacker. But if the request is met, even though the URL is clearly not meant to go anywhere, the hacker might be able to make use of it.

Using .htaccess as a Firewall

One of the best methods I’ve found against this kind of threat is an .htaccess firewall. It basically consists of rules that automatically block requests based on strings in the URL.

For example, there is no good reason for an opening bracket ([) to be in a URL. If a request is made using a URL that contains a bracket, then either the user has mistyped something or someone is looking for a security hole. Either way, generating a “403 Forbidden” page is good practice in this case.

RedirectMatch 403 [

Paste the line above in your .htaccess file to block any request that contains an opening bracket.

To guard against more than just brackets, you will need a more complex ruleset. Luckily, our awesome editor Jeff Starr has gone out of his way to create a great .htaccess ruleset. The latest iteration is called 5G Firewall52 and is freely available from Perishable Press for your copy-and-pasting pleasure.

The firewall is modular, so you can delete lines from it without breaking the functionality. If something goes wrong when you’re using it, you can usually track down the problem by deleting lines until it starts working again. Once you’ve found the offending line, you can delete it and paste back the rest.

Protecting Directories

On many servers, it is possible to view the contents of a directory simply by typing it in the URL bar.

http://myblog.com/wp-content/uploads/2011/08/

Visiting this typical URL for a WordPress blog will list the contents of that directory, showing all of the uploads from August 2011. You might want this, but you can also disable or fine tune it using the good ol’ .htaccess file.

Options -Indexes

Popping the above line into your .htaccess file will disable directory listings; so, users will get a “403 Forbidden” message if they try to view a directory. While many people seem to be aware of this, far fewer know of the other options besides allowing or disallowing access. You can control which file types are listed using the IndexIgnore directive. Take these three examples:

IndexIgnore *
IndexIgnore *.php 
indexIgnore *.jpg *.gif *.png

If directory listing is enabled, then the directory will be displayed in the first example, but no files will be listed because all will be ignored. The second example will list all files except ones with a .php extension. The third example will omit the three image types specified.

Note that some hosts (such as MediaTemple) disable directory browsing by default, so you won’t need to modify the .htaccess file. To verify this, just type a directory location in the URL bar and see what happens.

Additional Server-Level Protection

So far, the measures we have taken have nothing to do with our website’s actual code. However secure your code is, you will still need to implement something like what we did above. We don’t have time to look at all tips and tricks for .htaccess, but you can do quite a few other things:

  • Password-protect directories,
  • Use smart redirects,
  • Deny access based on IP or an IP range,
  • Force downloading of files,
  • Disable hotlinking,
  • The list goes on.

Look at the “Further Reading” section at the end of this article, and become good friends with your .htaccess file. It might seem daunting and confusing at first, but solid knowledge of how to use it will go a long way.

Protecting Against Malicious Users

The second type of problem that can arise is when someone performs an action that they are not supposed to do. This doesn’t necessarily mean that they intended to harm the website, but it could happen.

If users are listed somewhere in the admin part of your website, chances are that a link is displayed to delete each user. The link could point to the script in the following location:

http://mysite.com/admin/scripts/delete_user.php?user_id=5

This link is relatively obscure; that is, a normal user doesn’t have a good chance of stumbling on it. But if directory listings are enabled, then someone naughty could go to http://mysite.com/admin/scripts/, see that you have a delete_user.php file there, and make various requests to try to delete a user.

If the script does not check permission or intent, then anyone who visits the link above could delete user 5.

Authority and Intent

Whenever a user initiates an action, we need to take two things into consideration. Does the user have authority to perform the action (i.e. do they have permission)? If the user does have authority, do they also intend to complete the action (i.e. do they mean to do what they’re doing)?

WordPress has functions to help you make sure that both conditions are met before an action in the script is triggered. We will look at these in detail shortly. If you are building your website from scratch, then you will need to make sure that each user has associated permissions and that you know which action can be performed under which condition.

For example, you would probably want only administrators to be able to delete content from the website. Every time a user tries to delete content, you would need to make sure that they are actually an administrator — this is the “authority” part.

Intent is best described with an example. Let’s assume you can use the following link to delete a comment:

http://mysite.com/admin/scripts/delete_comment.php?comment_id=5

The script itself will check that the user is currently logged in and is an administrator, so it takes care of the authority check. Could someone still wreak havoc? Sure they could! A sneaky hacker could put a link on their own website pointing to the same location:

<a href="http://mysite.com/admin/scripts/delete_comment.php?comment_id=5">Super-Happy Times Here!</a>

Because everyone likes super-happy times, many users would click the link. In 99% of cases, nothing would happen, because those visitors would not be administrators of mysite.com. But if a logged-in administrator of mysite.com did click on the link, then the action would execute, even though the link was actually clicked from vilehackerperson.com.

You might think that the odds of this happening are astronomical. In a way you’d be right, but remember that a hacker can do this extremely easily and can automate it. Millions of people get spam email saying that Bill Gates will take away the Internet unless they pay $1,000. Most recipients don’t see the email or throw it out or mark it as spam or what have you, but perhaps 1 out of every 2 million people is lured in. A thousand bucks for basically doing nothing is not bad at all. And a hacker probably wouldn’t put the link on their own website; all they would need to do is hack a big website and embed the link there without anyone noticing.

Checking For Authority In WordPress

WordPress has a permissions system built in referred to as “Roles and Permissions3.” Capabilities are the basis of the whole system; roles are just a way to group a set of capabilities together.

If a user has the delete_posts capability, then they have the authority to delete posts. If a user has the edit_posts capability, then they can edit their posts. Quite a few capabilities are available, and you can even create your own.

Roles are basically groups of capabilities. A user with the role of “contributor” has three capabilities: read, delete_posts and edit_posts. These give the user the authority to read posts and to edit or delete their own posts. These capabilities could be granted individually to any user, but grouping them into frequently used bundles is much easier and more practical.

With that in mind, let’s look at how to use WordPress functions to ensure that a user has the authority to complete an action that they initiate.

if(current_user_can("delete_users")) {
    wp_delete_user(5);
}
else {
    die("You naughty, naughty person. Of course, you could just be logged out…");
}

Here, we’ve made sure that the user has the delete_users capability before they are able to complete the action. Don’t make premature assumptions when protecting your scripts; in many cases, especially those of authority, the intent is not malicious.

The current_user_can() function takes one argument, which can be a role or a permission. We could let “editors” (who don’t normally have the delete_users capability) delete users in the following way:

if(current_user_can("editor")) {
    wp_delete_user(5);
}
else {
    die("You must be an editor to delete a user");
}

Be careful with the method above because the roles are not inclusive. This function doesn’t require the user to be at least an editor; it requires them to be exactly an editor (if that makes sense). Because of this, I find it preferable to use capabilities, especially if I have modified the default permissions extensively.

Two other similar functions enable you to examine the capabilities of users other than the currently logged-in one.

if(user_can(5, "manage_links")) {
    echo "User 5 is allowed to manage links";
}
else {
    echo "Sadness! User 5 may not manage links";
}
if(author_can(1879, "update_themes")) {
    echo "The author of post #1879 is allowed to update themes";
}
else {
    echo "Oh noes, our friend, the author of post #1879 may not update themes";
}

The user_can() function checks whether a given user has the given capability (or role). The first argument is the user’s ID or a user object; the second argument is the name of the capability or role that we want to check for.

The author_can() function checks whether the author of a given post has the given capability (or role). The first parameter should be a post ID or a post object; the second is the capability or role that we are examining.

Checking For Intent In WordPress

Intent is a bit more difficult to check. In the good ol’ days, a check of $_SERVER['HTTP_REFERER'] was the way to go. This stored the page that the user came from. If the domain name was their own, then the user was probably OK… unless, of course, someone had gotten into their files and inserted a link that deleted the user’s database if they clicked on it as an administrator.

A newer more secure method was implemented in WordPress 2.03 — quite some time ago — called nonces. Nonce stands for “number used once” and is used frequently in cryptography to secure communications. It is a number that is generated before an action is initialized, then attached to the action’s call, and then checked before the action completes.

In WordPress, you would generally use nonces in one of two places: forms and normal links. Let’s look first at how to generate a nonce in a form.

Nonces in Forms

<form id="myform" method="post" action="myawesomescript.php">
    <h2>Enter an awesome word here</h2>
    <input type='text' name='word'>
    <?php wp_nonce_field( 'awesome_name_nonce') ?>
</form>

This will generate a hidden input field containing your generated nonce, which will be sent along with all of the form’s other data. The wp_nonce_field function takes four parameters:

  1. The first parameter is optional, but recommended because it gives the nonce a unique identifier.
  2. The second parameter is the name of the field. This is also optional and defaults to _wpnonce.
  3. The third parameter is boolean. If set to true, it will also send the referrer for validation.
  4. The fourth parameter is also a boolean and controls whether the field is echoed right then and there.

The resulting hidden field would look something like this:

<input type="hidden" id="_wpnonce" name="_wpnonce" value="d6d71w4664">

Setting all of this up won’t make a huge difference if it isn’t used when the form is actually processed. We need to check for the presence and the value of the nonce before allowing any actions to be performed. Here is one way to do that:

if (!wp_verify_nonce($_POST['_wpnonce'],'awesome_name_nonce') ) {
   die('Oops, your nonce didn't verify. So there.');
}
else {
   awesome_word_inserter($_POST["word"]);
}

Here, we’ve used the wp_verify_nonce() function to make sure that our nonce is correct. This function takes two parameters: the first is the value of the nonce field, and the second is the name of the action that we defined (this was the first parameter for the wp_nonce_field() function). If the nonce is verified, then the function will return true; otherwise, it will return false.

Nonces in Links

In some cases, you will want a link, instead of a form, to perform an action. This would typically look like our previous examples:

http://mysite.com/admin/scripts/deletethatthing.php?thing_id=231

To generate a nonce for a link, we can use the following method:

$base_url = "http://mysite.com/admin/scripts/deletethatthing.php?thing_id=231";
$nonce_url = wp_nonce_url( $base_url, "thingdeleter_nonce");
echo "<a href='".$nonce_url."'>Delete that thing</a>";

The resulting link would be something like this:

http://mysite.com/admin/scripts/deletethatthing.php?thing_id=231&_wpnonce=d6f77f1364

When we actually go to the script, we can check the nonce using the same method as before:

if (!wp_verify_nonce($_GET['_wpnonce'],'thingdeleter_nonce') ) {
   die('Oops, your nonce didn't verify. So there.');
}
else {
   delete_that_thing($_GET["thing_id"]);
}

Checking Authority And Intent At The Same Time

We need to look at both aspects at once; although, now that we’ve looked at all of the components, it won’t exactly be rocket science! Let’s take a simple link that lets the user delete a comment. We would have this on the page that lists comments:

$nonce_url = wp_nonce_url("http://mysite.com/scripts/delete_comment.php?comment_id=1451", "delete_comment_nonce");
echo "<a href='".$nonce_url."'>dispose of this comment</a>";

And here is the script itself:

if (wp_verify_nonce($_GET['_wpnonce'],'delete_comment_nonce') AND current_user_can("edit_comment")) {
   wp_delete_comment($_GET["comment_id"]);
}
else {
   die('Oops, your nonce didn't verify, or you are not permission-endowed enough.');
}

Data Security

Our work might seem to be done, but if you’ve been developing for a while, then you know it never is. An additional layer of security needs to be added to stop insecure data (or erroneous data) from entering our database. Adding this additional layer is called data sanitization.

A quick clarification: data sanitization refers to the process of cleaning up our data to make sure that nothing suspicious gets sent to the database. Validation refers to all of the checks we perform on data to make sure they are the types of data we need; it is typically done to ensure that the user has entered a valid email address, a well-formed URL, etc. The two terms are sometimes used interchangeably, and other methods may be similar, but they are quite different things. For our purposes, sanitization is a bit more important, because it has more to do with security.

The main thing we are trying to protect against is SQL injection. SQL injection is a technique used by hackers to exploit a database’s weaknesses. Take the following example:

// A hacker goes to your search field and searches for elephant' - note the apostrophe at the end. In the script, the following SQL is run:
SELECT ID, post_title FROM wp_posts WHERE post_title LIKE '%elephant'%'

In the example above, the user’s search for elephant' has resulted in unclosed quotes in your script. While the hacker might not be able to do much with this, an error message would be generated, indicating to them that at the very least you are not sanitizing your data.

In some cases, the SQL itself could be harmful or could give the hacker much more information than you’d like. Take the example of an administrator being able to enter a user’s log-in name in a form and getting back the user’s email address.

SELECT user_email FROM wp_users WHERE user_login = 'danielp'

If the hacker manages to perform an SQL injection attack, they could type ' OR 1=1 ' in the form, which would result in the following query:

SELECT user_email FROM wp_users WHERE user_login = '' OR 1=1 ''

This would return all email addresses in the database, because we would be retrieving all addresses for which the user’s log-in name is an empty string, or 1=1, which is always true.

There are two ways to protect against this kind of problem — implementing both is good practice. In round one, we validate the data. If an email address needs to be entered, we can filter out user data that does not conform to the format of email addresses. We simply make sure that the format is right, otherwise we redirect the user, stating that the address is invalid. If the data passes round one, we move to round two, where we remove all characters that could mess up the query. This usually entails escaping quotes so that they can be used only as actual quotes in the SQL query.

When working without a framework, you would typically use addslashes() or something similar, but WordPress offers its own solution…

Data Sanitization In WordPress

When communicating with the database in WordPress, the preferred method is to use the $wpdb class. You can read all about this in “WordPress Essentials: Interacting With the WordPress Database4.” The class offers a number of methods to alleviate your SQL injection worries.

Before jumping in, let’s look at some examples to get a basic understanding of how the class works.

// Perform any query
$wpdb->query("DELETE FROM wp_users WHERE user_id = 5");
// Get one column of data
$posts = $wpdb->get_col("SELECT post_title FROM wp_posts WHERE post_status = 'publish' ORDER BY comment_count DESC LIMIT 0,10");
// Get a row of data
$post = $wpdb->get_row("SELECT * FROM wp_posts WHERE ID = 1453");
// Get multiple rows and columns
$posts = $wpdb->get_results("SELECT ID, post_title, post_date FROM wp_posts WHERE post_type = 'publish' ORDER BY post_date DESC LIMIT 0, 12 ");
// Get a single value 
$author_id = $wpdb->get_var("SELECT post_author FROM wp_posts WHERE ID = 2563");
// Insert a record
$wpdb->insert("wp_postmeta", array("post_id" => 2323,  "meta_key" => "favorite_count", "meta_value" => 224 ), array("%d", "%s", "%d"));
// Update a record
$wpdb->update("wp_postmeta", array("meta_value" => 225), array("meta_key" => "favorite_count", "post_id" => 2323), array("%d"), array("%s", "%d"));

The insert() and update() methods are helper methods, and they’re great because, apart from modularizing your database interactions a bit, they also take care of sanitization for you. If you want to use the general query() method, though, you will need to take care of it on your own.

The easier way is just to use the escape() method:

$data = $wpdb->escape($_POST[about_me]);
$wpdb->query("UPDATE wp_usermeta SET meta_value = '$data' WHERE meta_key = 'description' AND user_id = 154  ");

A slightly harder but better way to go about this is to use the prepare() method. An example from the WordPress Codex illustrates this perfectly:

$metakey = "Harriet's Adages";
$metavalue  = "WordPress' database interface is like Sunday Morning: Easy.";
$wpdb->query( $wpdb->prepare( 
   "
      INSERT INTO $wpdb->postmeta
      ( post_id, meta_key, meta_value )
      VALUES ( %d, %s, %s )
   ", 
        10, 
   $metakey, 
   $metavalue 
) );

Further Protection Using Sanitization

Sanitization is a fairly big topic and requires quite some time to master. For now, you’ll be busy mostly determining which characters to allow and which to disallow, and then finding ways to parse out the latter. Some common needs are to parse HTML out of addresses, filter numbers out of strings, validate email addresses and so on, but you will need to implement your own solutions for more complex needs. See the “Further Reading” section for more on this topic.

Final Thoughts

The measures needed to secure a website cannot be discussed in a single book, let alone a poor article. There are many methods and topics we did not look at, such as advanced password encryption, salts and so on. But hopefully, by implementing what we’ve discussed, your website will be much safer. Hackers usually go for the weakest link, so if your website is not insanely popular and is fairly secure, you should be OK.

While I have a lot of experience in this field, I am far from being a security expert. If you know of any other or better methods, do share them in the comments. There is always something new to learn about website security.

General Reading

WordPress-Specific Reading

(al)

Footnotes

  1. 1 http://www.smashingmagazine.com/2011/11/10/securing-your-wordpress-website/
  2. 2 http://perishablepress.com/5g-firewall-beta/
  3. 3 http://codex.wordpress.org/Roles_and_Capabilities
  4. 4 http://www.smashingmagazine.com/2011/09/21/interacting-with-the-wordpress-database/
  5. 5 http://perishablepress.com/5g-firewall-beta/
  6. 6 http://users.telenet.be/ws36178/security/webmaster/htaccess.html
  7. 7 http://en.wikipedia.org/wiki/SQL_injection
  8. 8 http://www.unixwiz.net/techtips/sql-injection.html
  9. 9 http://www.tizag.com/mysqlTutorial/mysql-php-sql-injection.php
  10. 10 http://www.php.net/manual/en/function.filter-var.php
  11. 11 http://net.tutsplus.com/tutorials/php/sanitize-and-validate-data-with-php-filters/
  12. 12 http://codex.wordpress.org/Roles_and_Capabilities#edit_comment
  13. 13 http://www.garyc40.com/2010/04/ultimate-guide-to-roles-and-capabilities/
  14. 14 http://markjaquith.wordpress.com/2006/06/02/wordpress-203-nonces/
  15. 15 http://www.prelovac.com/vladimir/improving-security-in-wordpress-plugins-using-nonces
  16. 16 http://codex.wordpress.org/WordPress_Nonces
  17. 17 http://codex.wordpress.org/Class_Reference/wpdb
  18. 18 http://codex.wordpress.org/Data_Validation

↑ Back to topShare on Twitter

Daniel is not only a web developer who is in love with WordPress, but also the Editor of the Smashing WordPress section. He owns a company called Bonsai Shed where they make web apps and premium themes like Musico and Estatement.

Advertising
  1. 1

    Not sure about RedirectMatch 403 [ – can’t square brackets be used to pass array values in query strings? Check PHP’s parse_str. Obviously it’s not something that would come up often, but if someone blindly put that line in .htaccess, they might get confused down the line if this kind of query string gets used.

    0
    • 2

      Hi Steve,

      Thanks for bringing that up, I didn’t think people would actually read all that code :) However what you’re saying isn’t exactly what happens.

      While it is true that you use brackets to pass values in query strings the brackets need to be URL encoded. So instead of using ?something[]=2&something[]=3 you would need to use: something%5B%5D=2&something%5B%5D=3

      The bracket – like many other entities – needs to be url encoded before being used.

      0
      • 3

        so a hacker can just use url encoded strings to achieve their ill intentions anyway?

        0
        • 4

          It’s not quite as simple as that. While theoretically it is possible, the chances of being able to do serious damage with JUST the url string is astronomical. The site would have to be EXTREMELY poorly coded and the hacker would need to be awesome lucky. The only way this could work is if ?delete=4556 would delete that post and there is no login check and so forth.

          As far as I understand it the URL query method is used by hackers to find specific vulnerabilities. In other words, they don’t hack your site using it directly but it gives them a crumb of information they might be able to use.

          0
  2. 5

    Great post! I’m going through each one to test it out on a few of my sites.

    0
  3. 7

    No offence to author but securing Word Press? Good luck to you, as there are as many holes in this application as there are in a sieve. Word Press has always been dogged with security issues and will continue to do so because of the way in which it was designed and developed.

    Looking at recent source, there is no suggestion anything big will change in the future, and I do know what I’m talking about regards to application design and development.

    Basically it sucks, always has done and always will do so. Best to move on.

    -1
  4. 11

    I’m pretty sure WordPress has been secure in terms of directory browsing for a long time now.

    J.

    0
    • 12

      Yes, by placing index.php in each directory. So if you try to see the folder, you will actually see an empty php file. Yet, this is not valid for the uploads folder.

      0
  5. 13

    Nice useful information.Thank you for sharing.

    0
    • 14

      Trackback Howdy! Do you know if they make any plugins to asssit with Search Engine Optimization? I’m trying to get my blog to rank for some targeted keywords but I’m not seeing very good gains. If you know of any please share. Kudos!

      0
  6. 15

    Theme and plugin authors should use the built in esc_ functions even in administration menus to protect against cross site scripting and other security holes.

    Read about how to use these here – http://codex.wordpress.org/Data_Validation

    Here is a great presentation on Theme and Plugin security by Mark Jaquith – http://wordpress.tv/2011/01/29/mark-jaquith-theme-plugin-security/

    And another more recent one I just found while retrieving that url – http://wordpress.tv/2011/09/07/mark-jaquith-jon-cave-brad-williams-plugin-security-showdown/

    0
  7. 16

    You should switch rows 2 and 5 in the server code under Checking Authority And Intent At The Same Time ;)

    0
    • 17

      Argh, I changed it around, thanks! That just proves that being an idiot is the leading reason for being hacked! :)

      0
  8. 18

    Thanks Daniel! I have been hacked a few times in the past weeks and have implemented a few of the things you have listed here. Guess what I’m going to be doing this weekend??

    0
  9. 20

    Great post, many thanks.

    Dan

    0
  10. 21

    Great suggestions.

    Another opportunity for increased security is preventing access to the login page itself. You could require a specific query string to be entered or protect the page with an htaccess level auth requirement.

    Joe

    0
    • 22

      I replied to this comment by Joe yesterday, but checking today I see that my comment has vanished.

      It linked to a plugin (Login Dongle) in the wordpress.org site, it followed the guidelines for comments, and It was not spam.

      0
  11. 23

    Why would you use a CMS or Blog engine that has soooo many security holes in it that you have to fix out of the box. I have gone back and forth on what CMS/Blog engine to use. This article actually sealed the fate of WordPress in my eyes. I have seen multiple article about “How to secure WordPress”. The simple fact that there are so many articles out there on this same subject leads me to believe that
    1. The WordPress core developers done care enough to put simple safeguards against hackers and spammers out of the box. Meaning that they don’t really give a rats @** about their users.
    2. That WordPress enthusiast, though very smart and able, are blind to the fact that they waste time every single time they need to deploy a WordPress site by adding all of this extra protection because the Core WordPress team didn’t do it for them.

    I know the product if free, but there are plenty of other free CMS’/blog engines that come with built in security and safeguards with out having to make the users/developers put in all this work to make sure their site is protected.
    Take Umbraco for example, Free, very secure CMS, but when someone found a hole in the security, the very next day they sent out a patch that automatically prompted you to install the patch. Problem solved right away.

    It just seems like a sad state of affairs that it started out as a good product and idea, but now they don’t want to add security to their core development to enable them to stay viable as a usable product. Just seems like a mess of extra work and hassle to get a site built.
    Just my thoughts.

    0
    • 24

      Hi Carlos (and Les),

      I am actually not a security expert so I would love to hear what the exact security holes in WordPress are. I don’t use it exclusively but I do use it quite a lot and I haven’t really had any security problems before.

      None of the methods I mentioned are for filling security holes in WordPress. These are things that WordPress has out of the box. There isn’t any framework which automagically protects your site for you. WordPress has nonce functionality but you obviously have to use it to actually use it.

      While there ARE frameworks which do things for you these are less flexible since the internal systems are harder to modify. I think WordPress has excellent security functions but you need to know about them to use them effectively. Other frameworks may do things automatically for you but they are less modular. II don’t think either is better or worse, it’s a matter of what you need.

      Apart from that, please do share the actual security issues as I want to keep my own site’s secure as well and I’m sure others want to do the same!

      0
    • 25

      Carlos – as much as anything it’s because of the flexibility and open-sourced-ness that anyone with relatively minimal knowledge can write a plug-in or template which is horribly, horribly vulnerable and any WP-user can install it. And when they install it on shared hosting…..
      WP can work wonderfully but for the majority of users it’s like a “Build your own front door for free” kit…. “A lock? Why would I need a lock? What is a lock, anyway?”

      0
  12. 26

    Daniel,
    Thanks for the reply.
    I am not a security expert by any means as well. But the title of your article is “Securing Your WordPress Website”, which leads me to believe there are security holes in WordPress. Maybe it should have been “Shoring Up Your WordPress Website” or “Adding Additional Safeguards to your WordPress Website”.
    Like I said before, I have going back and forth with deciding on digging into WordPress full time and seeing and reading articles like these just seems counter active to the whole process of deciding between WordPress and a competitor.
    But you point out a hacker can access many parts of a WordPress website, do potential damage or sometimes even the server by simply entering a known URL query and finding the paths of files and entering that way. Something the WordPress core devs could do would be to the ability to add the .htaccess code in there. I have seen this everywhere in other “Secure WordPress” posts.
    Granted there are more articles mainly because of the sheer volume WordPress has out on the market. Ease of use out of the box, great. Adding Themes out of the box, great. But then I run into articles such as this that “beef” up WordPress that it doesn’t do out of the box, just makes me second guess any decision about WordPress.

    Data sanitation to prevent SQL injections as in the article is another issue I find a bit mistrusting. The fact that it could be that easy to inject a bunch of SQL or product pages upon pages of malicious pages and content just turns me away.

    Maybe my knowledge of WordPress is probably not adequate enough to fully comprehend why WordPress does not have as many security issues as it seems, it just seems like it from reading multiple articles like this posting.

    I do acknowledge your knowledge of WordPress. I do think it is a great site or blog builder.
    I know no website or CMS is entirely secure, especially if your password in so common a 4 year old to hack your site. But like I said, reading multiple articles that “beef” up security for WordPress is a hard pill to swallow when the competition looks a little bit brighter. That is just me. To each their own.
    Great article though. Good to know if the future if I do get clients who would like to use WordPress as their CMS of choice. For my personal site, not for me. Like a said… to each their own.

    @DNALogic
    The flexibility and open-source-ness I really dig. I am all about open source anything. It breeds great products and community. The vulnerable plugins is anyones issue. Just like downloading an application for your computer, you don’t know unless it comes from a trusted source whether it has vulnerabilities.
    I completely agree with your last analogy too. Many users do use it out of the box and don’t take the safeguards recommended in this article and don’t use what is out there. But that is the trust people are putting into WordPress when they download it. I guess that is my point. The trust is there for general user who I guess just expect too much. You really need to have developers knowledge or be looking at these types of articles regularly to know that there are ways WordPress could be more secure and how to do them. But for many general users, the hackfests continue on them.

    0
    • 27

      Hi Carlos,

      First of all, I find your comments very positive, I was getting ready for a lot of flaming :) I’m happy that SM users are awesome enough to have a nice debate.

      I think that misunderstandings about security arise because there are two parts to the story. WordPress can not do anything about server security. You can hack any site, regardless of the CMS used, with a luckily guessed URL (this is not exactly true as is but an ok example). This is something which concerns server security and has nothing to do with the CMS (in most cases).

      You are right, perhaps the title is misleading a bit. The article is about how to use all the nice security tools WordPress offers you and also how to add additional server level security.

      I might actually do another article about this, or just a short one on my own website because I am not sure that “regular” users would have trouble. I think security is the biggest issue when you start using your own code for things. As an out-of-the-box user your experience should be pretty secure since the default theme and many others are well coded. Only when you start choosing dodgy themes or creating faulty is when you should be worried.

      I am not exactly sure that that last paragraph holds true, so I’ll do some research on it. Thanks for your thoughts, much of what you say is true and I;m glad it can be said without profanity and being rude :)

      0
      • 28

        Daniel,

        Thanks again. I don’t usually feel the need to get into heated arguments about things usually. Especially on forums. I don’t think it breeds good community and debate. That is why I despise trollers who just go on forums to start arguments for no reason. I just had some varying questions that you answered for me. I appreciate that.
        I always know that there are so many products out there and so many options that I don’t feel the need to say one thing is better than another because everyone has different tastes and different knowledge sets. I am always willing to learn new things because the way the world of web development and design is going these days, one technology may be in on month and the next there may be something completely new the next.
        Thanks again.

        0
        • 29

          It is not WordPress, that would be your host. I’ve seen so many hosting companies nowadays with outdated version of WordPress. People with little or no knowledge will rather use auto-installer and setup a WordPress via hosting provider and that’s where the problem lays.

          If the latest (current) is 3.2.1 and your host is using 3.1 well sure there will be issues. Another thing. Hosting providers and their user credentials every time you need to update WordPress or Plugins is also obstacle here, this should be automated, people don’t like using their FTP credentials and I don’t blame them.

          Outdated anything (not just WordPress) will be a potential security issue, please make a note of that.

          Cheers,
          Emil

          0
          • 30

            WordPress now powers around 17% of the active domains on the internet. That’s an interesting stat to keep in mind when pontificating about its security characteristics. The most popular software attracts the most attention from those who want to compromise stuff, and as a result, WordPress is continually pounded by such people.

            The highly competent folks that I know on the WordPress core team are obsessed with security. WordPress core is actually highly secure, and getting more so all the time. It has a well developed validation and sanitization API. But sadly, some 3rd party developers to not use these features resulting in security problems … but these problems are due to bad 3rd party plugins and themes, not an insecure core.

            Is the core completely secure? No — nothing is, and I’m sure there are vulnerabilities yet to be discovered. But WordPress is nowhere near as flimsy as some in this thread make it out to be. If it were, the results would be very drastic.

            0
          • 31

            I totally agree with you on this. I didn’t really bring this up in the article because I don’t need to convince those who have a knack for coding or those who have worked with multiple frameworks and I have no chance of convincing the haters :)

            I would say that the top 5-10 frameworks out there are all very secure. Weather or not developers utilize the security is a different question. If I have the most modern technology protecting my house it is worthless if I don’t switch it on.

            As a little sidebar: I have NEVER seen a professional developer write any angry comments. For some reason professionals disagree calmly :)

            0
  13. 32

    Thanks Daniel, for as good content.

    0
  14. 33

    Thank you for writing this post. I found the .htaccess info especially helpful. Since I am not a programmer, you lost me half way through the post, but I did learn some new things that will help me on my blog.

    I am a long time reader. Thanks again!

    0
  15. 34

    Gregory Cornelius

    November 11, 2011 1:07 pm

    I am surprised that you didn’t mention SSL. To really secure admin activity, you need to encrypt all of the admin requests so that the session cookie is not leaked. Google “firesheep WordPress” if you want more information.

    0
    • 35

      Thanks for that Gregory, I’ll check it out, I didn’t know about that plugin. There are a few other tricks you can use to further security like adding a server level login before you can even load any admin page and so on, as I said we could write books and books about this, all suggestions are welcome :)

      0
  16. 36

    Hello All,

    My only frustration with this post is that WordPress itself hasn’t already thought of this stuff and incorporated more secure measures into it’s core platform – or at least in the formation of an all inclusive security plugin like JetPack so it is simple and easy to setup and monitor ongoing. This plugin could be updated along the way to address new threats so we aren’t having to change small things on every installation every time there is a new problem.

    I am using WP almost exclusively as the platform I develop on so anything that decreases the potential for having to go back into every installation to fix things would be HUGE! I don’t ming loggin in to update plugins, but not to troubleshoot and fix things.

    My two cents :)

    Thanks for the post!

    0
  17. 37

    Daniel,

    Thanks for your interesting post.

    There are of course many vulnerabilities with open source and one good way of staying safe is to always have the latest version of WP.

    Updating your .htaccess is also recommended along in checking for loop holes via your admin console.

    Don’t also forget to protect your .htaccess file itself:

    Security and Protection plugins if anyone is interested:
    http://wordpressapi.com/2011/04/14/best-wordpress-plugins-for-wordpress-security-and-protection/

    0
  18. 38

    Use mod_security and OWAS rules. More than 99% of the stuff mentioned above will be taken care of. Much better than getting carried away with htaccess rules and slowing down Apache without any benefit.

    Also, the “5G” ruleset should really be implemented at an httpd.conf level instead of htaccess. The performance will be more practical. Having a labyrinthine htaccess is just stupid.

    0
    • 39

      Hi Erick,

      While you are right about httpd, most people don’t have direct access to this file, their only choice is htaccess. The 5G ruleset is hardly a labyrinth though.

      0
  19. 40

    Its really informative ,I think every word press user must implement this

    0
  20. 41

    Great article. Here’s another security measure worth mentioning: Change the default login url by moving WP to its own directory.

    Instructions and more info: http://codex.wordpress.org/Giving_WordPress_Its_Own_Directory

    0
    • 42

      Hi Jeremy,

      Yep this is a good idea, I have many of my WP sites set up like this (although not because of security). This setup also allows you to manage your whole set (including the core files) with version control very easily.

      0
  21. 43

    Very useful tips for word press sites. I am using many plugins to protect my web site

    I like the BulletProof Security Wp plugin. But i am not sure about this plugin.

    0
  22. 44

    Great tips. One thing is missing in securing your web site and that is taking regular backups of the database and the file structure. My favorite plugin for doing this is Backupbuddy by Ithemes.

    A lot of people ask what do backups have to do with securing your web site. The answer is lots, This is the one way to protect your data and providing you the ultimate security.

    0
  23. 45

    Very nice article. If it’s ok with you, I’d like to translate it and publish in my blog. Of course keeping the credit and links back to here. It is on the work already and if you want I can post back here once done.

    Thank you again :)

    0
  24. 46

    Daniel Schutzsmith

    November 24, 2011 5:26 pm

    I’ve had a few WordPress sites that were hacked with vulnerabilities in some wordpress plugins I believe. I had to take several measures to ensure they didn’t happen again. The best possible plugin I’ve found to help with this is Bulletproof Security.

    Their actual website looks sketchy but the plugin does its job and then some. The pro version will actually scan your files for intrusions as well – extremely handy.

    Also, start using Website Defender, it can help secure any website not just wordpress ones. Its been invaluable in sending me regular emails when one of our clients needs a plugin updated or to tell me if files have changed on their server (we’re currently scanning 20+ like this.

    I’m in no way affiliated with either of these services, just thought I’d let everyone know what has worked from someone who has literally had to clean up hacked sites in the past few months.

    0
  25. 47

    Some plugins of my choice:
    1. Semisecure Login Reimagined – extra protection to login page
    2. Block Bad Queries (BBQ)
    3. Limit Login Attempts – gives 3 tries to write password, than blocks the user out for customizable time. It also changes the error message when you write wrong password, for existing username to “Incorrect username or password”

    Thanks for the article Daniel, I learned a lot of new things

    0
  26. 48

    The article seems to be only for the Apache… Anything for NGINX lovers… :)

    0
  27. 49

    Terrific work! That is the type of info that are meant to be shared across the web. Shame on Google for now not positioning this post upper! Come on over and talk over with my web site . Thanks =)

    0

↑ Back to top