Outsourced IT Partner
Support · systems · strategy
© 2026
One person, one business — IT support here, websites at webology.online.
One person, one business — IT support here, websites at webology.online.
WordPress Security Hardening Guide 2024
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