WordPress Security Tips
This article will cover many recommended methods to secure your WordPress installation. The latest version of WordPress can always been found on their official download page: Download WordPress or Latest WordPress Zip Archive. WordPress has a much more extensive treatment of the topic in their documentation. Here we go over some of the most basic measures you can take to help ensure the security of your site.
Keep WordPress Updated
One of the most vital and important issues is to ensure that your WordPress install is kept fully updated. Older versions of WordPress can be exploitable, leaving your website and sometimes servers vulnerable to attacks or malicious activity. Further, almost every updated version of WordPress specifically references security patches.
We have an article available for upgrading WordPress available here: How can I upgrade WordPress? Since WordPress 3.7, automatic updates have been enabled by default and more information regarding these automatic updates can be found here: Configured Automatic Updates.
Besides keeping the actual core WordPress install updated, keeping plugins and themes fully updated is just as important, if not even more important. In the WordPress Admin Panel, the plugins page and themes page will both advise if plugins or themes need to be updated. Check out the screenshots below for examples of plugins and themes that have updates available.
Strong Passwords
Always make sure to use strong passwords for any authenticated access. For example, your admin user (which shouldn’t be named admin, if it is change it!) and your MySQL database passwords. You can see more about secure password generation in our How can I generate … ? article.
Choosing Plugins for WordPress
We all have our list of favorite plugins, however, we rarely check to see if those plugins have any added vulnerabilities, besides WordPress’s own vulnerabilities. However, oftentimes it’s the plugins and themes that can make it even less secure. If you find a plugin that you feel you need to install, make sure you research the plugin first, verifying that no exploits or vulnerabilities exist for it. Similarly, many themes have plugins builtin to them, so you will want to research these carefully as well. For example, a couple years ago there was a vulnerability in revslider that was patched, but many themes had bundled it in and didn’t update it to apply the patch. So a lot of site administrators were vulnerable to the exploit and didn’t even realize they were running the plugin. So you will want to carefully research each plugin and theme you consider before installing.
Security Plugins
Here’s a list of suggested Security Plugins that can help with your WordPress security:
- WordFence has several useful features, including checking the core files–as well as the plugin and theme files–for changes likely to indicate site compromise. It can also be configured to send you an email when either the WordPress core or any of the installed plugins or themes have updates available. It also can throttle certain types of traffic to reduce server load, and lock out IP addresses that pretend to be Google that aren’t. You can read more about this plugin on their
page in the WordPress plugin catalog. But, one thing that WordFence does not do, is log the failed logins in files where they can be read, for example by CSF/LFD. This brings us to:
- WP-fail2ban is a plugin that causes login successes and failures to be written to server logs, so that firewalls like CSF/LFD can be configured to read it. The plugin is designed to work with a firewall called Fail2Ban which conflicts with CSF/LFD, but CSF/LFD can be configured to read the logs for the entries generated by this WordPress plugin.
Disabling Unnecessary Files & Access
The default WordPress installation retains numerous files in the installation path that can provide information to potential hackers. For example, the readme.html in the document root of the WordPress installation provides the installed version. The installed version may contain vulnerabilities, allowing the attacker to pinpoint an exploit point. You can check if your site has this problem as follows:
$ curl -s http://domain.tld/readme.html | grep Version
Version 4.0.1
This is just one example. It is recommended to disable access to the following files:
- All license* files. Including the ones provided in plugins and/or themes.
- All readme* files. Including the ones provided in plugins and/or themes.
- wp-config-sample.php
- xmlrpc.php
You could remove all of these files, however, a simple way to simply remove permissions or access to these files would be to remove permissions on the file(s). For this example, we will be chmodding all of the referenced files to 000. Which can easily be done via shell terminal using the following examples. Note: You’ll want to replace /home/user/public_html/wordpress/
with the absolute path to your WordPress install’s document root.
# find /home/user/public_html/wordpress/ -type f -iname "*readme*"
# find /home/user/public_html/wordpress/ -type f -iname "*license*" ! -iname "*.php"
# find /home/user/public_html/wordpress/ -type f -iname "*readme*" -exec chmod 000 {} +
# find /home/user/public_html/wordpress/ -type f -iname "*license*" ! -iname "*.php" -exec chmod 000 {} +
# chmod 000 /home/user/public_html/wordpress/wp-config-sample.php /home/user/public_html/wordpress/xmlrpc.php
Disabling PHP Execution from wp-content
Many exploits, especially due to plugin vulnerabilities, operate in part by running php scripts from directly within the wp-content folder, or even the uploads folder itself. The WordPress core files do not need to run any php scrpits directly from these folders. Some plugins may, but keep in mind that these are often the same plugins that more often will have this type of vulnerability. To help protect against this type of exploit, you may want to add the following lines to an .htaccess file in the wp-content directory:
<FilesMatch "\.php$">
Order Deny,Allow
Deny from All
</FilesMatch>
Disabling Directory Index Listing
Many servers default to allow directory index listing. For example when visiting a typical WordPress install, if you add wp-content/plugins/ to the address, ie, a url like http://securewp.com/wp-content/plugins/
, you would be able to see all plugins on the site as well as the files within the directories. To ensure this option is not available, place an .htaccess file containing
in your wp-content and wp-includes directories.
$ echo "Options -Indexes" >> /home/user/public_html/wordpress/wp-content/.htaccess
$ echo "Options -Indexes" >> /home/user/public_html/wordpress/wp-includes/.htaccess
Alternatively, if you would like to disable directory index listing serverwide, this can be done in WHM at
Home >> Service Configuration >> Apache Configuration >> Global Configurationas described here, by making sure the “Indexes” box is not checked, in the Directory "/" Options
section.
Disabling Theme / Plugin Editing
While this is a user friendly feature of WordPress, it also opens your installation to overlooked vulnerabilities. This option removes the ability for the WordPress installation to edit plugins or themes. It is recommended to ensure your website is finished with development and then add the following constant to your wp-config.php file.
define(‘DISALLOW_FILE_EDIT’,true);
Of course, if you have this constant enabled and would like to turn the feature back on, you can simply comment out the constant from your wp-config.php file.
Securing Themes
Check your installed theme’s header file for the following:
<meta name="generator" content="WordPress <?php bloginfo('version'); ?>" />
If this line of code exists, remove it or comment it out. This will disable the theme from providing version enumeration.
Disable Login Errors
Login errors can provide useful information to hackers. For example, if they use a correct username, it will respond with invalid password, but at now they know they’ve used a correct username to keep trying with. To disable this, add the following code to your installed theme’s functions.php:
add_filter('login_errors',create_function('$a', "return null;"));
Replace Original Authentication Unique Keys and Salts
Your wp-config.php file contains authentication keys and salts. You can regenerate and replace the existing keys and salts at any time, forcing all users to log in again. It is recommended to do this occasionally. Lines 45-82 of wp-config.php will contain these keys, looking similar to the following:
define('AUTH_KEY', '/asT;[zOn.E~|d~Dh*{zf./31s&n-%vry7I*x+Ddz%h_Pu,#;%,;01+2=:@h@Jz)UC!Zts');
define('SECURE_AUTH_KEY', 'zp{Re)}Rdnexx{?ujlN[+tWJrTXr$z+s1DKfj4cegdPo:]h12B=5j?fRlRhiGh`-');
define('LOGGED_IN_KEY', '~=GX1e<~$R3aIN8Vy,+Ddz%hlR.S!/e<e!fvWdRkrM~KjoB}xmA*hwr=E[]gC~U');
define('NONCE_KEY', 'x QECT!B~d)+^u7@+:A/`p+Ddz%h*,/rf;d~#gaLRz p[yO8+-P%B<Sga[+=sCKj');
define('AUTH_SALT', 'aWw@%,ca:22w^y=iHGGWw8>xD%(6-fS4+gj.ulHKh%h%UeXFHw#m0:]0RbX-{NL_~p');
define('SECURE_AUTH_SALT', 'b[,14@Xg8E--.oh#)y8/dK@x412[n?+5k!Rh%i#$9 o$pe >5i=|G?~mHnLsG-7+');
define('LOGGED_IN_SALT', 'HfJe:G!A6q>kSu>To 9W;YxCY?73K Pk3;ih%-)H7Dpn#j>6F3@R.,CVT&yn+$/]');
define('NONCE_SALT', 'Z@ t_&KRIjgEfsUbR|bo>^Q~$LYo*,W#G<R0+Ih%l`g1X?:*>V`_vb3Ii9+z}eJt');
You can use WordPress’s API to generate new salt values here.
Change Default ‘wp_’ Database Prefixes
Using the default, predictable wp_ prefixes in your database make SQL injections much easier. Altering these prefixes can help secure your WordPress installation even further. It’s best to ensure this is done during the WordPress installation, doing it after is much more difficult, however I’ve outlined the steps required here.
- Update the table_prefix constant in wp-config.php to the new prefix. The line looks like this:
$table_prefix = 'wp_';
- For this example, we’re changing wp_ to wp_khsec_.
$table_prefix = 'wp_khsec_;
- Using either PHPMyAdmin or MySQL via command line, you’ll now have to rename all tables in the WordPress database to the new prefix.
mysql> show tables;
+-----------------------+
| Tables_in_securewp_wp |
+-----------------------+
| wp_commentmeta |
| wp_comments |
| wp_links |
| wp_options |
| wp_postmeta |
| wp_posts |
| wp_term_relationships |
| wp_term_taxonomy |
| wp_terms |
| wp_usermeta |
| wp_users |
+-----------------------+
11 rows in set (0.00 sec)
mysql> RENAME TABLE wp_commentmeta TO wp_khsec_commentmeta;
- This will need to be done for each table in the database.
- Lastly, a few tables have fields that need to be updated as well. Ensure that you modify these fields:
- wp_khsec_options > wp_user_roles
- wp_khsec_usermeta > wp_capabilities, wp_user_level, wp_autosave_draft_ids
- wp_autosave may not be in your tables.
Ensure Secure Server Side Permissions
Ensuring that your server is using proper server side permissions is a critical topic, but may require some contemplation to choose what’s right for you.
The typical recommendation for your PHP Handler is DSO+mod_ruid2, or Litespeed Web Server, which requires permissions of 644 for files and 755 for folders. But, we want to make sure we don’t add unneeded permissions to files we specifically removed some of the permissions from above. To ensure all files and folders have the correct permissions in your WordPress installation, you can perform the following:
find /home/user/public_html/wordpress/ -type d -perm /022 -exec chmod -c go-w {} +
find /home/user/public_html/wordpress/ -type f -perm /133 -exec chmod -c a-x,go-w {} +
This should remove permissions that shouldn’t be needed for any file or folder while using DSO+mod_ruid2 without re-adding permissions that were purposefully removed.