Technical Recipes

How to make WordPress website secure

After you passed the installation stage and brought up the WordPress screen in browser, it's just half way done the set up procedure. With the basic configuration to make 
WordPress work leaves security threats on the server, especially the database access information is a plain text in the wp-config.php file.
 
In order to enhance the security of your WordPress website, there are tasks recommended to complete as below:
 
1 Apply all updates
 
   You should always update WordPress to the latest version. When a new version of WordPress is available you will receive an update message in your WordPress Admin Screens.
 
   There are two methods for updating - the easiest is the one-click update, which will work for most people. If it doesn't work, or you just prefer to be more hands-on, you can follow the manual update process.
 
   WARNING: The upgrade process will affect all files and folders included in the main WordPress installation. This includes all the core files used to run WordPress. If you have made any modifications to those files, your changes will be lost.
 
   For a step-by-step instructions on installing and updating WordPress, see reference [5].
 
2 Back up WordPress website
 
   Back up your database regularly, and always before an upgrade.
 
   Before you get started, it's a good idea to back up your website. This means if there are any issues you can easily restore your website. Complete instructions to make a backup can be found in the WordPress Backups section of the Codex.
 
   Your WordPress database contains every post, every comment and every link you have on your blog. If your database gets erased or corrupted, you stand to lose everything you have written.
 
   Most hosts back up the entire server, including your site, but it takes time to request a copy of your site from their backups, and a speedy recovery is critical. You need to learn how to back up your own site files and restore them.
 
3 Move content, plug-in folders to separate location from the WordPress installation
 
    For backup, update and security reasons, it's a good practice to move the user specific content outside the WordPress installation directory. See http://bingobo.info/blog/recipes/how-to-backup-mysql-database.jsp for how.
 
4 Move wp-config.php outside the document root
 
    NOTE: Since Version 2.6, wp-config.php can be moved to the directory directly above the WordPress application directory. If the parent directory is web root, it does not help. If not, you have to set the path to the open_basedir in the PHP.ini, which makes it exposed, and also potentially expose server logs, backups, etc to attackers.
 
open_basedir = "/var/www/vhosts/example.com/httpdocs/;/var/www/vhosts/example.com/phpdocs/;/tmp/"
 
    If you move to your user specific directory under web root, and use .htaccess to protect it, it will not be affected by update. Say if you move to /phpdocs sub-directory under web root, add the following lines in the .htaccess under /phpdocs:
 
    <Files wp-config.php>
         order allow,deny
         deny from all
    < /Files>
 
    You can move the wp-config.php to any directory by creating a new wp-config.php in the WordPress directory with the following code:
 
    /** Absolute path to the WordPress directory. */
    if ( !defined('ABSPATH') )
        define('ABSPATH', dirname(__FILE__) . '/');
    /** Location of your WordPress configuration. */
    require_once(ABSPATH . '../phpdocs/wp-config.php');
 
5 Protect the log folders
 
    Configuring error logging can be a bit tricky. First of all, default PHP error log and display settings are set in the php.ini file, which you may or may not have access to. If you do, they should be set to the desired settings for live PHP pages served to the public. It's strongly recommended that no error messages are displayed to the public and instead routed to an error log. Further more, error logs should not be located in the publicly accessible portion of your server.
 
    Obviously, you will want different settings for your development environment. If your staging copy is on the same server, or you don't have access to php.ini, you will need to override the default settings at run time. It's a matter of personal preference whether you prefer errors to go to a log file, or you prefer to be notified immediately of any error, or perhaps both. Here's an example that reports all errors immediately that you could insert into your wp-config.php file:

    @ini_set( 'log_errors', 'Off' );
    @ini_set( 'display_errors', 'On' );
    @ini_set( 'error_reporting', E_ALL );
    define( 'WP_DEBUG', true );
    define( 'WP_DEBUG_LOG', false );
    define( 'WP_DEBUG_DISPLAY', true );

    The default debug log file is /wp-content/debug.log. Placing error logs in publicly accessible locations is a security risk. Ideally, your log files should be placed above you site's public root directory. If you can't do this, at the very least, set the log file permissions to 600 and add this entry to the .htaccess file in the root directory of your WP installation:

    <Files debug.log>
        Order allow,deny
        Deny from all
    < /Files>

6 Force SSL when login
 
    To easily enable (and enforce) administration over SSL, there are two constants that you can define in your blog's wp-config.php file. It is not sufficient to define these constants in a plugin file; they must be defined in your wp-config.php file. You must also already have SSL configured on the server and a (virtual) host configured for the secure server before your site will work properly with these constants set to true. Note that you cannot use name based virtual hosting to identify different SSL servers.
 
    FORCE_SSL_LOGIN is for when you want to secure logins so that passwords are not sent in the clear, but you still want to allow non-SSL admin sessions (since SSL can be slow).

    define( 'FORCE_SSL_LOGIN', true );

    FORCE_SSL_ADMIN is for when you want to secure logins and the admin area so that both passwords and cookies are never sent in the clear. This is the most secure option.

    define( 'FORCE_SSL_ADMIN', true );

7 Use anti-virus protection plug-in
 
8 Enhance MySQL security
 
    8.1 Block remote access from iptables rule:

    /sbin/iptables -A INPUT -p tcp –dport 3306 -j DROP

    8.2 Make MySQL server bind only to localhost:

    bind-address=127.0.0.1

A more comprehensive guide can be found in reference [12].