WordPress powers 43% of all websites, making it a prime target for hackers. This comprehensive security guide will help you protect your WordPress site from common threats and vulnerabilities.

1. Secure Hosting Foundation

Choose Security-Focused Hosting

  • Managed WordPress Hosting: Built-in security features
  • SSL Certificates: Always use HTTPS
  • Server-Level Security: Firewall, DDoS protection
  • Regular Backups: Automated daily backups

Server Configuration


# .htaccess security rules
# Protect wp-config.php

order allow,deny
deny from all


# Disable directory browsing
Options -Indexes

# Protect .htaccess file

order allow,deny
deny from all
satisfy all


# Block suspicious requests
RewriteEngine On
RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} proc/self/environ [OR]
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR]
RewriteCond %{QUERY_STRING} base64_(en|de)code[^(]*\([^)]*\) [OR]
RewriteCond %{QUERY_STRING} (<|%3C)([^s]*s)+cript.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} (\<|%3C).*iframe.*(\>|%3E) [NC]
RewriteRule .* - [F]
            

2. WordPress Core Security

Secure wp-config.php


// wp-config.php security enhancements
// Disable file editing
define('DISALLOW_FILE_EDIT', true);
define('DISALLOW_FILE_MODS', true);

// Force SSL for admin
define('FORCE_SSL_ADMIN', true);

// Disable XML-RPC
add_filter('xmlrpc_enabled', '__return_false');

// Change security keys regularly
define('AUTH_KEY',         'your-unique-auth-key');
define('SECURE_AUTH_KEY',  'your-unique-secure-auth-key');
define('LOGGED_IN_KEY',    'your-unique-logged-in-key');
define('NONCE_KEY',        'your-unique-nonce-key');
define('AUTH_SALT',        'your-unique-auth-salt');
define('SECURE_AUTH_SALT', 'your-unique-secure-auth-salt');
define('LOGGED_IN_SALT',   'your-unique-logged-in-salt');
define('NONCE_SALT',       'your-unique-nonce-salt');

// Limit login attempts
define('WP_FAIL2BAN_BLOCKED_USERS', array('admin', 'administrator', 'root'));

// Hide WordPress version
remove_action('wp_head', 'wp_generator');
            

3. User Account Security

Strong Authentication


// functions.php - Enhanced user security
// Enforce strong passwords
function enforce_strong_passwords($errors, $sanitized_user_login, $user_email) {
    if (isset($_POST['pass1']) && !empty($_POST['pass1'])) {
        $password = $_POST['pass1'];

        if (strlen($password) < 12) {
            $errors->add('password_length', 'Password must be at least 12 characters long.');
        }

        if (!preg_match('/[A-Z]/', $password)) {
            $errors->add('password_uppercase', 'Password must contain at least one uppercase letter.');
        }

        if (!preg_match('/[a-z]/', $password)) {
            $errors->add('password_lowercase', 'Password must contain at least one lowercase letter.');
        }

        if (!preg_match('/[0-9]/', $password)) {
            $errors->add('password_number', 'Password must contain at least one number.');
        }

        if (!preg_match('/[^A-Za-z0-9]/', $password)) {
            $errors->add('password_special', 'Password must contain at least one special character.');
        }
    }

    return $errors;
}
add_action('user_profile_update_errors', 'enforce_strong_passwords', 0, 3);

// Force password reset for weak passwords
function check_weak_passwords() {
    $users = get_users();
    foreach ($users as $user) {
        $password_strength = wp_check_password_strength($user->user_pass);
        if ($password_strength < 3) {
            wp_set_password(wp_generate_password(16, true), $user->ID);
            wp_mail($user->user_email, 'Password Reset Required', 'Your password has been reset for security reasons.');
        }
    }
}
add_action('wp_scheduled_delete', 'check_weak_passwords');
            

Two-Factor Authentication


// Custom 2FA implementation
function setup_two_factor_auth($user_id) {
    $secret = random_bytes(16);
    $encoded_secret = base32_encode($secret);
    update_user_meta($user_id, '2fa_secret', $encoded_secret);

    return $encoded_secret;
}

function verify_2fa_code($user_id, $code) {
    $secret = get_user_meta($user_id, '2fa_secret', true);
    if (!$secret) return false;

    require_once 'path/to/GoogleAuthenticator.php';
    $ga = new PHPGangsta_GoogleAuthenticator();

    return $ga->verifyCode($secret, $code, 2);
}

// Require 2FA for admin users
function require_2fa_for_admin($user, $password) {
    if (user_can($user, 'administrator')) {
        if (!isset($_POST['2fa_code']) || !verify_2fa_code($user->ID, $_POST['2fa_code'])) {
            return new WP_Error('2fa_required', 'Two-factor authentication required.');
        }
    }
    return $user;
}
add_filter('wp_authenticate_user', 'require_2fa_for_admin', 10, 2);
            

4. Database Security

Database Hardening


// wp-config.php database security
// Change default table prefix
$table_prefix = 'wp_secure_';

// Database connection security
define('DB_HOST', 'localhost:3306:/var/lib/mysql/mysql.sock');
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', 'utf8mb4_unicode_ci');

// functions.php - Database security functions
function secure_database_queries() {
    global $wpdb;

    // Remove unnecessary data
    $wpdb->query("DELETE FROM {$wpdb->posts} WHERE post_status = 'auto-draft' AND post_date < DATE_SUB(NOW(), INTERVAL 7 DAY)");
    $wpdb->query("DELETE FROM {$wpdb->comments} WHERE comment_approved = 'spam' AND comment_date < DATE_SUB(NOW(), INTERVAL 30 DAY)");

    // Clean up orphaned metadata
    $wpdb->query("DELETE pm FROM {$wpdb->postmeta} pm LEFT JOIN {$wpdb->posts} wp ON wp.ID = pm.post_id WHERE wp.ID IS NULL");
    $wpdb->query("DELETE cm FROM {$wpdb->commentmeta} cm LEFT JOIN {$wpdb->comments} wc ON wc.comment_ID = cm.comment_id WHERE wc.comment_ID IS NULL");
}

// Schedule weekly database cleanup
if (!wp_next_scheduled('weekly_database_cleanup')) {
    wp_schedule_event(time(), 'weekly', 'weekly_database_cleanup');
}
add_action('weekly_database_cleanup', 'secure_database_queries');
            

5. File System Security

File Permissions


# Correct file permissions
# Directories: 755 or 750
find /path/to/wordpress/ -type d -exec chmod 755 {} \;

# Files: 644 or 640
find /path/to/wordpress/ -type f -exec chmod 644 {} \;

# wp-config.php: 600
chmod 600 wp-config.php

# .htaccess: 644
chmod 644 .htaccess
            

File Integrity Monitoring


// functions.php - File integrity checking
function check_core_file_integrity() {
    $core_files = array(
        ABSPATH . 'wp-config.php',
        ABSPATH . 'wp-load.php',
        ABSPATH . 'wp-blog-header.php'
    );

    foreach ($core_files as $file) {
        if (file_exists($file)) {
            $current_hash = md5_file($file);
            $stored_hash = get_option('file_hash_' . basename($file));

            if ($stored_hash && $current_hash !== $stored_hash) {
                // File has been modified
                wp_mail(get_option('admin_email'), 'File Integrity Alert',
                       "Core file modified: " . basename($file));
            }

            update_option('file_hash_' . basename($file), $current_hash);
        }
    }
}

// Check file integrity daily
if (!wp_next_scheduled('daily_integrity_check')) {
    wp_schedule_event(time(), 'daily', 'daily_integrity_check');
}
add_action('daily_integrity_check', 'check_core_file_integrity');
            

6. Security Plugins

Recommended Security Plugins

  • Wordfence Security: Comprehensive security suite
  • Sucuri Security: Malware scanning and cleanup
  • iThemes Security: 30+ security measures
  • All In One WP Security: User-friendly security

Custom Security Plugin


// Custom security plugin structure
class CustomWordPressSecurity {

    public function __construct() {
        add_action('init', array($this, 'init_security'));
        add_action('wp_login_failed', array($this, 'log_failed_login'));
        add_filter('authenticate', array($this, 'check_login_attempts'), 30, 3);
    }

    public function init_security() {
        // Hide login errors
        add_filter('login_errors', function() {
            return 'Invalid credentials.';
        });

        // Disable user enumeration
        if (!is_admin() && isset($_GET['author'])) {
            wp_redirect(home_url());
            exit;
        }
    }

    public function log_failed_login($username) {
        $ip = $_SERVER['REMOTE_ADDR'];
        $attempts = get_transient('failed_login_' . $ip) ?: 0;
        $attempts++;

        set_transient('failed_login_' . $ip, $attempts, 900); // 15 minutes

        if ($attempts >= 5) {
            $this->block_ip($ip);
        }

        // Log the attempt
        error_log("Failed login attempt: $username from $ip (Attempt: $attempts)");
    }

    public function check_login_attempts($user, $username, $password) {
        $ip = $_SERVER['REMOTE_ADDR'];
        $blocked = get_transient('blocked_ip_' . $ip);

        if ($blocked) {
            return new WP_Error('too_many_attempts', 'Too many failed login attempts. Try again later.');
        }

        return $user;
    }

    private function block_ip($ip) {
        set_transient('blocked_ip_' . $ip, true, 3600); // Block for 1 hour

        // Notify admin
        wp_mail(get_option('admin_email'), 'IP Blocked',
               "IP address $ip has been blocked due to multiple failed login attempts.");
    }
}

new CustomWordPressSecurity();
            

7. Malware Detection and Removal

Custom Malware Scanner


// Simple malware detection
function scan_for_malware() {
    $suspicious_patterns = array(
        'eval\(',
        'base64_decode\(',
        'gzinflate\(',
        'str_rot13\(',
        'preg_replace.*\/e',
        '\$_POST\[',
        '\$_GET\[',
        'shell_exec\(',
        'system\(',
        'exec\(',
        'passthru\(',
        'file_get_contents\(.*http'
    );

    $scan_directories = array(
        ABSPATH,
        WP_CONTENT_DIR . '/themes/',
        WP_CONTENT_DIR . '/plugins/',
        WP_CONTENT_DIR . '/uploads/'
    );

    foreach ($scan_directories as $directory) {
        $files = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($directory)
        );

        foreach ($files as $file) {
            if ($file->isFile() && preg_match('/\.(php|js)$/', $file->getFilename())) {
                $content = file_get_contents($file->getPathname());

                foreach ($suspicious_patterns as $pattern) {
                    if (preg_match('/' . $pattern . '/i', $content)) {
                        // Suspicious file found
                        wp_mail(get_option('admin_email'), 'Malware Detected',
                               "Suspicious code found in: " . $file->getPathname());
                        break;
                    }
                }
            }
        }
    }
}

// Schedule weekly malware scan
if (!wp_next_scheduled('weekly_malware_scan')) {
    wp_schedule_event(time(), 'weekly', 'weekly_malware_scan');
}
add_action('weekly_malware_scan', 'scan_for_malware');
            

8. Backup and Recovery

Automated Backup System


// Custom backup function
function create_wordpress_backup() {
    $backup_dir = WP_CONTENT_DIR . '/backups/';
    if (!file_exists($backup_dir)) {
        wp_mkdir_p($backup_dir);
    }

    $date = date('Y-m-d-H-i-s');
    $backup_file = $backup_dir . 'backup-' . $date . '.zip';

    // Create zip archive
    $zip = new ZipArchive();
    if ($zip->open($backup_file, ZipArchive::CREATE) !== TRUE) {
        return false;
    }

    // Add files to backup
    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator(ABSPATH),
        RecursiveIteratorIterator::LEAVES_ONLY
    );

    foreach ($files as $file) {
        if (!$file->isDir()) {
            $filePath = $file->getRealPath();
            $relativePath = substr($filePath, strlen(ABSPATH));

            // Skip backup directory and large files
            if (strpos($relativePath, 'wp-content/backups/') === false &&
                $file->getSize() < 50 * 1024 * 1024) { // Skip files larger than 50MB
                $zip->addFile($filePath, $relativePath);
            }
        }
    }

    $zip->close();

    // Database backup
    $db_backup = $backup_dir . 'database-' . $date . '.sql';
    $command = sprintf(
        'mysqldump -h %s -u %s -p%s %s > %s',
        DB_HOST,
        DB_USER,
        DB_PASSWORD,
        DB_NAME,
        $db_backup
    );
    exec($command);

    // Clean old backups (keep last 7)
    $backups = glob($backup_dir . 'backup-*.zip');
    if (count($backups) > 7) {
        array_multisort(array_map('filemtime', $backups), SORT_ASC, $backups);
        unlink($backups[0]);
    }

    return $backup_file;
}

// Schedule daily backups
if (!wp_next_scheduled('daily_backup')) {
    wp_schedule_event(time(), 'daily', 'daily_backup');
}
add_action('daily_backup', 'create_wordpress_backup');
            

9. Security Monitoring

Security Event Logging


// Comprehensive security logging
class SecurityLogger {
    private $log_file;

    public function __construct() {
        $this->log_file = WP_CONTENT_DIR . '/security.log';
        $this->init_hooks();
    }

    private function init_hooks() {
        add_action('wp_login', array($this, 'log_login'), 10, 2);
        add_action('wp_logout', array($this, 'log_logout'));
        add_action('wp_login_failed', array($this, 'log_failed_login'));
        add_action('user_register', array($this, 'log_user_registration'));
        add_action('delete_user', array($this, 'log_user_deletion'));
    }

    public function log_event($event, $details = array()) {
        $log_entry = array(
            'timestamp' => current_time('mysql'),
            'ip' => $_SERVER['REMOTE_ADDR'],
            'user_agent' => $_SERVER['HTTP_USER_AGENT'],
            'event' => $event,
            'details' => $details
        );

        $log_line = json_encode($log_entry) . "\n";
        file_put_contents($this->log_file, $log_line, FILE_APPEND | LOCK_EX);
    }

    public function log_login($user_login, $user) {
        $this->log_event('user_login', array(
            'user_id' => $user->ID,
            'username' => $user_login,
            'role' => implode(', ', $user->roles)
        ));
    }

    public function log_logout() {
        $user = wp_get_current_user();
        $this->log_event('user_logout', array(
            'user_id' => $user->ID,
            'username' => $user->user_login
        ));
    }

    public function log_failed_login($username) {
        $this->log_event('failed_login', array(
            'username' => $username
        ));
    }
}

new SecurityLogger();
            

Security Checklist

  • ✅ Strong hosting with SSL certificate
  • ✅ WordPress core, themes, and plugins updated
  • ✅ Strong passwords and 2FA enabled
  • ✅ File permissions properly configured
  • ✅ Security plugins installed and configured
  • ✅ Regular backups automated
  • ✅ Malware scanning enabled
  • ✅ Security monitoring and logging active
  • ✅ Database secured and optimized
  • ✅ Login attempts limited

Need WordPress Security Audit?

I can perform a comprehensive security audit and implement these hardening measures for your WordPress site.

Get Security Audit