How to Secure a WordPress Website

Posted on

How to Secure a WordPress Website

How to Secure a WordPress Website

Securing your How to Secure a WordPress Website is crucial to protect it from hackers and malware. An unsecured WordPress site can be easily compromised, resulting in issues like spam, phishing attacks, and blacklisting by Google. Fortunately, there are several key steps you can take to lock down your WordPress security and ensure your site remains safe and functional. Implementing these measures diligently is vital for maintaining the integrity of your online presence. This guide details actionable steps you can take today to enhance your website’s defenses. For those seeking to fortify their online presence, understanding how to How to Secure a WordPress Website is paramount. Let’s dive into the essentials of How to Secure a WordPress Website.

1. Use a Strong Password

The first step is using a strong password for your WordPress administrator account. Your admin login controls the entire site, so it’s the most critical thing to protect. Here are some password tips:

  • Use a combination of uppercase and lowercase letters.
  • Include numbers and symbols.
  • Make it at least 12 characters long.
  • Avoid using personal information like names, birthdays, or common words.
  • Use a password manager to generate and store strong passwords.

Enable two-factor authentication wherever possible for an extra layer of security on top of your password.

Alternative Solution: Passkey Authentication

While strong passwords and two-factor authentication (2FA) are excellent, a more modern and inherently secure approach is to implement passkey authentication. Passkeys, based on WebAuthn standards, replace passwords entirely with cryptographic key pairs tied to a specific device.

  • Explanation: Passkeys eliminate the risk of password-based attacks like phishing or brute-forcing because there’s no password to steal. The user’s authentication is based on possession of the device (e.g., phone, laptop) and a biometric factor (e.g., fingerprint, face ID) or a PIN. This significantly enhances security and improves the user experience by simplifying login.

  • Implementation: Implementing passkeys in WordPress requires a plugin. Look for a plugin that supports WebAuthn and integrates with the WordPress authentication flow. These plugins typically handle the registration and authentication processes. While code implementation is handled by the plugin itself, you’ll need to configure the plugin with your website and ensure it’s compatible with your theme and other plugins.

Another Alternative Solution: Passwordless Login via Magic Link

Another approach to enhance security and user experience is passwordless login using magic links. This eliminates the need for users to remember passwords.

  • Explanation: When a user tries to log in, they enter their email address. The system sends a unique, time-sensitive link to their email. Clicking the link automatically logs the user in. This avoids the vulnerabilities associated with passwords, such as weak passwords, password reuse, and phishing attacks.

  • Implementation:

    <?php
    /**
     * Plugin Name: Passwordless Login
     * Description: Enables passwordless login via magic link.
     * Version: 1.0
     */
    
    // Enqueue scripts and styles
    add_action( 'wp_enqueue_scripts', 'passwordless_login_enqueue_scripts' );
    function passwordless_login_enqueue_scripts() {
        wp_enqueue_script( 'passwordless-login', plugin_dir_url( __FILE__ ) . 'passwordless-login.js', array( 'jquery' ), '1.0', true );
        wp_localize_script( 'passwordless-login', 'passwordlessLogin', array(
            'ajax_url' => admin_url( 'admin-ajax.php' ),
            'nonce' => wp_create_nonce( 'passwordless-login-nonce' )
        ));
    }
    
    // Add login form fields
    add_action( 'login_form', 'passwordless_login_form' );
    function passwordless_login_form() {
        ?>
        <p>Enter your email to receive a login link:</p>
        <p>
            <label for="passwordless-email">Email<br>
            <input type="email" name="passwordless-email" id="passwordless-email" class="input" value="" size="20"></label>
        </p>
        <p class="submit">
            <input type="button" name="wp-submit" id="wp-passwordless-submit" class="button button-primary button-large" value="Send Login Link">
        </p>
        <?php
    }
    
    // AJAX handler to send the magic link
    add_action( 'wp_ajax_passwordless_send_link', 'passwordless_send_link' );
    add_action( 'wp_ajax_nopriv_passwordless_send_link', 'passwordless_send_link' );
    function passwordless_send_link() {
        check_ajax_referer( 'passwordless-login-nonce', 'nonce' );
    
        $email = sanitize_email( $_POST['email'] );
        if ( ! is_email( $email ) ) {
            wp_send_json_error( 'Invalid email address.' );
        }
    
        $user = get_user_by( 'email', $email );
        if ( ! $user ) {
            wp_send_json_error( 'No user found with that email address.' );
        }
    
        $token = wp_generate_password( 32, true, true );
        update_user_meta( $user->ID, 'passwordless_token', $token );
        update_user_meta( $user->ID, 'passwordless_token_expiry', time() + ( 60 * 15 ) ); // 15 minutes
    
        $login_link = add_query_arg( array(
            'passwordless_login' => 'true',
            'user_id' => $user->ID,
            'token' => $token
        ), wp_login_url() );
    
        $subject = 'Your Login Link';
        $message = 'Click this link to log in: ' . $login_link;
        wp_mail( $email, $subject, $message );
    
        wp_send_json_success( 'Login link sent to your email.' );
    }
    
    // Handle the login link
    add_action( 'init', 'passwordless_login_handler' );
    function passwordless_login_handler() {
        if ( isset( $_GET['passwordless_login'] ) && $_GET['passwordless_login'] == 'true' ) {
            $user_id = intval( $_GET['user_id'] );
            $token = sanitize_text_field( $_GET['token'] );
    
            $user = get_user_by( 'id', $user_id );
            if ( ! $user ) {
                wp_die( 'Invalid user.' );
            }
    
            $stored_token = get_user_meta( $user_id, 'passwordless_token', true );
            $token_expiry = get_user_meta( $user_id, 'passwordless_token_expiry', true );
    
            if ( $token !== $stored_token || time() > $token_expiry ) {
                wp_die( 'Invalid or expired login link.' );
            }
    
            wp_set_auth_cookie( $user_id );
            wp_set_current_user( $user_id );
            do_action( 'wp_login', $user->user_login );
    
            delete_user_meta( $user_id, 'passwordless_token' );
            delete_user_meta( $user_id, 'passwordless_token_expiry' );
    
            wp_redirect( admin_url() );
            exit;
        }
    }
    ?>
    jQuery(document).ready(function($) {
        $('#wp-passwordless-submit').click(function(e) {
            e.preventDefault();
            var email = $('#passwordless-email').val();
    
            $.ajax({
                url: passwordlessLogin.ajax_url,
                type: 'POST',
                data: {
                    action: 'passwordless_send_link',
                    email: email,
                    nonce: passwordlessLogin.nonce
                },
                dataType: 'json',
                success: function(response) {
                    if (response.success) {
                        alert(response.data);
                    } else {
                        alert(response.data);
                    }
                }
            });
        });
    });

    Explanation:

    1. Plugin Structure: The code is structured as a WordPress plugin.
    2. Enqueuing Scripts: The passwordless_login_enqueue_scripts function enqueues a JavaScript file (passwordless-login.js) and localizes it with necessary data like the AJAX URL and nonce.
    3. Login Form: The passwordless_login_form function adds a new form to the WordPress login page, asking for the user’s email.
    4. AJAX Handler: The passwordless_send_link function handles the AJAX request when the user submits their email. It checks the nonce, validates the email, generates a unique token, stores it as user meta with an expiry time, and sends an email with a login link.
    5. Login Link Handler: The passwordless_login_handler function checks for the passwordless_login parameter in the URL. If present, it validates the user ID and token, logs the user in, and redirects them to the admin area.
    6. JavaScript: The JavaScript code handles the AJAX request to send the login link.

    Note: This is a basic implementation and should be further secured and customized for production use. It’s also crucial to handle error cases and user feedback properly. Consider using a dedicated plugin for a more robust solution.

2. Limit Login Attempts

Brute force login attacks are very common on WordPress. To prevent this, install a plugin like Login LockDown that limits the number of attempts from a single IP address. After a certain number of failed logins, that IP will be locked out. This makes brute force attacks much more difficult.

Configure the plugin to lock out IPs after 6 failed attempts, for a duration of 60 minutes. Check the box to lockout after a combination of user and password failures. This prevents attacks that try multiple usernames with a single password.

Alternative Solution: Implement a Captcha on the Login Page

While limiting login attempts is good, attackers can still try a limited number of attempts from many different IPs. A CAPTCHA presents a challenge that’s easy for humans but difficult for bots, effectively stopping automated brute-force attacks.

  • Explanation: By adding a CAPTCHA to the login page, you can prevent bots from repeatedly trying different usernames and passwords. This significantly reduces the effectiveness of brute-force attacks, even if they are distributed across multiple IP addresses.

  • Implementation: Many WordPress security plugins (like Wordfence, iThemes Security) include CAPTCHA functionality for the login page. Alternatively, you can use a dedicated CAPTCHA plugin. After installing the plugin, you will need to configure it with the appropriate API keys (if required by the CAPTCHA service, such as reCAPTCHA) and enable it for the login form.

Another Alternative Solution: Using a Honeypot Field

A honeypot field is a technique used to detect and deter bots from submitting forms, including login forms.

  • Explanation: A honeypot field is a form field that is intentionally left blank by human users but is often filled in by bots. By checking if this field is filled, the system can identify and block bot submissions.

  • Implementation:

    <?php
    // Add a honeypot field to the login form
    add_action( 'login_form', 'add_honeypot_field' );
    function add_honeypot_field() {
        echo '<p style="display:none;">
            <label for="honeypot">Honeypot</label>
            <input type="text" name="honeypot" id="honeypot" value="" />
        </p>';
    }
    
    // Check the honeypot field on login
    add_action( 'wp_authenticate', 'check_honeypot_field' );
    function check_honeypot_field( $user ) {
        if ( ! empty( $_POST['honeypot'] ) ) {
            wp_die( 'You are a bot!' ); // Or redirect to a safe page
        }
    }
    ?>

    Explanation:

    1. Add Honeypot Field: The add_honeypot_field function adds a hidden input field named "honeypot" to the login form. The style="display:none;" hides the field from human users.
    2. Check Honeypot Field: The check_honeypot_field function is hooked into the wp_authenticate action. It checks if the "honeypot" field is filled. If it is, it means a bot has likely filled it, and the function terminates the login process and displays a message (or redirects the user).

    Note: This is a simple implementation. A more robust solution might include logging the bot’s IP address or using more sophisticated bot detection techniques. This can also be combined with limiting login attempts.

3. Change Default Admin Username

Hackers widely target the default admin username on WordPress. Change this to a non-standard name that won’t be guessed.

Some good ways to create a secure admin username include:

  • Using a random string of characters.
  • Combining words with numbers and symbols.
  • Making it long and complex.

Avoid anything that identifies you personally or is connected to your site’s name.

Alternative Solution: Disable Direct Login by ID

While changing the username is helpful, attackers can still try to discover valid user IDs. Disabling direct login by ID prevents attackers from targeting specific user accounts, even if they know the user ID.

  • Explanation: WordPress allows logging in using the user ID. By disabling this, you force attackers to guess usernames, adding an extra layer of security.

  • Implementation:

    <?php
    // Disable login by ID
    add_filter( 'wp_authenticate', 'block_id_login', 20, 1 );
    function block_id_login( $user ) {
        $username = $_POST['log'];
        if ( is_numeric( $username ) ) {
            return new WP_Error( 'invalid_username', __( 'Usernames cannot be numeric.' ) );
        }
        return $user;
    }
    ?>

    Explanation:

    • block_id_login function: This function checks if the username submitted in the login form ($_POST['log']) is numeric.
    • is_numeric( $username ): This checks if the username is a number (i.e., a user ID).
    • WP_Error: If the username is numeric, the function returns a WP_Error object, preventing the login and displaying an error message.
    • add_filter: This filter hooks the block_id_login function into the wp_authenticate filter, which is run during the authentication process.

Another Alternative Solution: Implement Username Blacklisting

In addition to changing the default username, you can proactively block common and easily guessable usernames during registration.

  • Explanation: This technique prevents users (or attackers creating accounts) from using usernames like "admin," "administrator," "test," etc., that are frequently targeted in attacks.

  • Implementation:

    <?php
    // Function to check if the username is in the blacklist
    function is_username_blacklisted( $username ) {
        $blacklist = array( 'admin', 'administrator', 'test', 'user', 'wpadmin' ); // Add more usernames to the list
        return in_array( strtolower( $username ), $blacklist );
    }
    
    // Filter to block blacklisted usernames during registration
    add_filter( 'sanitize_user', 'block_blacklisted_usernames', 10, 3 );
    function block_blacklisted_usernames( $username, $raw_username, $strict ) {
        if ( is_username_blacklisted( $username ) ) {
            return 'blacklisted_username'; // Return a flag to indicate the username is blacklisted
        }
        return $username;
    }
    
    // Action to display an error message when a blacklisted username is used
    add_action( 'registration_errors', 'display_blacklisted_username_error', 10, 3 );
    function display_blacklisted_username_error( $errors, $sanitized_user_login, $user_email ) {
        if ( $sanitized_user_login == 'blacklisted_username' ) {
            $errors->add( 'username_denied', __( '<strong>ERROR</strong>: That username is not allowed. Please choose a different one.', 'your-text-domain' ) );
        }
        return $errors;
    }
    ?>

    Explanation:

    1. is_username_blacklisted function: This function checks if a given username is in the $blacklist array. You can customize the $blacklist array to include any usernames you want to prevent from being used.
    2. block_blacklisted_usernames function: This function is hooked into the sanitize_user filter. It calls is_username_blacklisted to check if the username is blacklisted. If it is, it returns the string ‘blacklisted_username’ which acts as a flag.
    3. display_blacklisted_username_error function: This function is hooked into the registration_errors action. It checks if the $sanitized_user_login is equal to ‘blacklisted_username’. If it is, it adds an error message to the $errors object, which will be displayed to the user during registration.

4. Use Strong Hosting Provider and Complex Credentials

Choose a provider with expertise in WordPress and security:

  • Look for providers offering managed WordPress hosting.
  • Check for features like automatic updates, malware scanning, and firewalls.
  • Read reviews and compare security features.

Your web hosting account credentials guard access to your site’s server. Use the same secure password practices for these as your WordPress login:

  • Long, complex passwords.
  • Unique passwords not used elsewhere.
  • Password manager.

Enable two-factor authentication at the host level too if available.

Also ensure you change any default credentials that may have come preset with your hosting plan.

Alternative Solution: Implement SSH Key Authentication for Server Access

Instead of relying solely on passwords for server access (SSH), use SSH key authentication. This is significantly more secure.

  • Explanation: SSH key authentication uses a pair of cryptographic keys: a private key that resides on your computer and a public key that’s placed on the server. When you connect to the server, your computer uses the private key to prove your identity. Because the private key never leaves your computer, it’s much harder for attackers to steal or intercept your credentials.

  • Implementation:

    1. Generate SSH Key Pair: Use a tool like ssh-keygen (available on most Linux and macOS systems) to generate a key pair.

      ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
    2. Copy Public Key to Server: Use ssh-copy-id or manually copy the contents of your public key (~/.ssh/id_rsa.pub) to the ~/.ssh/authorized_keys file on your server.

      ssh-copy-id user@your_server_ip
    3. Disable Password Authentication (Optional, but Recommended): Edit the SSH configuration file (/etc/ssh/sshd_config) on your server and set PasswordAuthentication to no. Restart the SSH service after making the changes.

      PasswordAuthentication no

Another Alternative Solution: Regularly Audit Server Logs for Suspicious Activity

Even with strong hosting and secure credentials, it’s crucial to proactively monitor server logs for any signs of intrusion or unauthorized access attempts.

  • Explanation: Analyzing server logs (e.g., access logs, error logs, authentication logs) can reveal suspicious patterns, such as failed login attempts, unusual requests, or attempts to access sensitive files. This allows you to detect and respond to security threats before they cause significant damage.

  • Implementation: Use a log analysis tool like GoAccess or Logwatch to automate the process of analyzing server logs. These tools can generate reports, highlight suspicious activity, and alert you to potential security issues.

    1. Install a Log Analysis Tool: Install GoAccess on your server.

    2. Configure the Tool: Configure GoAccess to analyze your web server’s access logs.

      goaccess /var/log/apache2/access.log -o /var/www/html/report.html
    3. Schedule Regular Reports: Set up a cron job to generate daily or weekly reports and email them to you.

      0 0 * * * goaccess /var/log/apache2/access.log -o /var/www/html/report.html && mail -s "GoAccess Report" your_email@example.com < /var/www/html/report.html

5. Install Security Plugins

Plugins provide additional ways to lock down WordPress beyond what’s available out of the box. Here are some must-have security plugins:

Wordfence

Wordfence offers an enterprise-grade firewall, malware scans, blocking of known malicious IPs, and audit logging for changes. It’s the most comprehensive security plugin available.

Key Features:

  • Web Application Firewall
  • Malware Scanning
  • Login Security
  • Real-time Threat Intelligence

iThemes Security

iThemes Security makes it easy to implement many basic security best practices in one plugin. It “hardens” the site with features like:

  • Hiding login URL
  • Disabling file editing
  • Changing database prefix

This takes WordPress beyond its default settings to further reduce vulnerabilities.

Wordfence and iThemes Security together provide a robust security foundation. The firewall and malware protection of Wordfence combined with the hardening and extra protections of iThemes makes an unbeatable combo.

Alternative Solution: Implement a Custom Content Security Policy (CSP)

While security plugins are valuable, they might not always cover every specific security need. Implementing a custom Content Security Policy (CSP) offers fine-grained control over what resources your website is allowed to load, mitigating various types of attacks.

  • Explanation: A CSP is an HTTP header that instructs the browser which sources of content (e.g., scripts, stylesheets, images) are permitted to load. By defining a strict CSP, you can prevent the browser from loading unauthorized content, reducing the risk of cross-site scripting (XSS) attacks, clickjacking, and other security vulnerabilities.

  • Implementation:

    <?php
    // Function to add the CSP header
    function add_content_security_policy_header() {
        $csp = "default-src 'self'; script-src 'self' 'unsafe-inline' https://example.com; style-src 'self' 'unsafe-inline' https://example.com; img-src 'self' data:; font-src 'self';";
        header( "Content-Security-Policy: " . $csp );
    }
    // Hook the function to the wp_headers action
    add_action( 'wp_headers', 'add_content_security_policy_header' );
    ?>

    Explanation:

    • add_content_security_policy_header function: This function defines the CSP header and sets the directives.
      • default-src 'self';: Allows resources from the same origin by default.
      • script-src 'self' 'unsafe-inline' https://example.com;: Allows scripts from the same origin, inline scripts (use with caution), and scripts from https://example.com.
      • style-src 'self' 'unsafe-inline' https://example.com;: Allows styles from the same origin, inline styles (use with caution), and styles from https://example.com.
      • img-src 'self' data:;: Allows images from the same origin and data URIs.
      • font-src 'self';: Allows fonts from the same origin.
    • add_action: This hooks the function to the wp_headers action, which is triggered when WordPress sends HTTP headers.

Another Alternative Solution: Implement Subresource Integrity (SRI)

Complementary to CSP, Subresource Integrity (SRI) ensures that files fetched from CDNs or other external sources haven’t been tampered with.

  • Explanation: SRI adds a cryptographic hash to the <script> or <link> tag. The browser calculates the hash of the fetched file and compares it to the specified hash. If the hashes don’t match, the browser refuses to execute the file, preventing the execution of malicious code injected into the file.

  • Implementation: When including external resources, generate the SRI hash and add it to the integrity attribute:

    <link rel="stylesheet" href="https://example.com/style.css" integrity="sha384-oqVuAfW9rCwFGHpjRYmvVVt2QqZm7uh4bzhmxu9n7V9V+E+J9KjU7fL9KjU5fF" crossorigin="anonymous">
    <script src="https://example.com/script.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>

    Explanation:

    • integrity attribute: Contains the cryptographic hash of the resource.
    • crossorigin attribute: Set to anonymous for resources served from a different origin.

    You can generate the SRI hash using online tools or command-line utilities like openssl.

6. Limit Plugins

Too many unnecessary plugins can bog down your site’s performance and also increase vulnerabilities. Each plugin expands your attack surface, especially ones that are poorly coded, not updated, or add more login accounts.

Regularly audit the plugins on your site. Remove any that aren’t essential, like inactive ones or those with minimal usage.

For those you keep, maintain them by:

  • Keeping them updated.
  • Checking for security vulnerabilities.
  • Removing unused plugins.

Also limit use of premium commercial plugins, which may have undisclosed security issues. When possible, choose free open source alternatives that are more transparent.

7. Strong User Passwords

Any user accounts you create for visitors/subscribers on your site should also follow good password practices.

Require them to use secure passwords by enforcing these rules:

  • Minimum length requirement.
  • Complexity requirements.
  • Password expiration policies.

This keeps brute force attacks on user accounts to a minimum.

You can enforce stronger passwords for users with a plugin like Force Strong Passwords.

8. Secure wp-config.php

The wp-config.php file contains database credentials and keys. It can be used to gain access if publicly accessible.

There are a few ways to lock this file down:

  • Move it above the web root.
  • Restrict access via .htaccess.
  • Set file permissions to 400 or 440.

9. Avoid Exposing Version Numbers

By default WordPress exposes its version number in the generator meta tag, RSS feeds, and REST API endpoints. This can help attackers target specific known vulnerabilities.

Use a plugin like Remove Generator Tag to remove version numbers from places like:

  • HTML source code.
  • RSS feeds.
  • REST API responses.

10. Use SFTP Over FTP

When managing your WordPress files, always use SFTP rather than regular FTP. SFTP is encrypted for secure transfer of files while FTP sends everything in plain text.

SFTP helps prevent sniffing of credentials or files during transfers. Ensure your hosting provider offers SFTP access as the preferred option over unencrypted FTP.

11. Unique Salts

WordPress salts provide some randomness to hashes to protect passwords and cookies. The default salts should be customized per site for enhanced security.

Install a plugin like Unique Salts to generate new unique salts. Then update your wp-config.php with the custom salts. This prevents exposing common defaults.

12. Disable PHP Execution

Some servers allow executing PHP code uploads for things like file attachment thumbnails. This can lead to arbitrary code execution vulnerabilities.

If possible, disable PHP code execution privileges in wp-config.php:

// Disallow PHP code execution
define( 'DISALLOW_FILE_MODS', true );

Also check with your hosting provider to disable PHP execution privileges at the server level when not needed.

13. Use HTTPS Everywhere

Enable HTTPS sitewide and redirect all HTTP traffic to HTTPS to encrypt connections. This protects credentials and data from interception on insecure WiFi networks.

The really simple SSL plugin makes enabling SSL easy by handling everything like obtaining certificates and configuring WordPress. Just install, activate, and enable automated HTTPS redirection.

14. Limit Access

Reduce what visitors can do on your site by limiting access only to what’s needed. For example:

  • Disable user registration if not required.
  • Limit comment posting to registered users.
  • Disable trackbacks and pingbacks.

The fewer avenues available to exploit, the better. Disable anything superfluous that may expose attack vectors.

15. Use Recaptcha

reCAPTCHA blocks bots and other internet nuisances from interacting with your site. Installing it protects you from automated brute force login attacks, spam registrations, and other malicious activities.

Get reCAPTCHA keys for your site and set it up to secure:

  • Login form.
  • Registration form.
  • Comment form.

This requires humans to pass a quick validation test before submitting data, limiting bots and abusive traffic.

16. Change Default Database Prefix

The default WordPress database table prefix of wp_ makes it obvious what software you are running. Obscure this by changing to a custom prefix like:

  • xyz_
  • wp123_
  • randomstring_

Update wp-config.php with your custom prefix. This makes it slightly harder for attackers to target WordPress specifically in your database.

17. Avoid Duplicating Content

Scrapers and content thieves target WordPress sites with duplicate content issues. Avoid copying content between staging sites or duplicating posts/pages.

Also prevent indexing any development or staging sites publicly. Keep them behind authentication until ready to launch.

Duplicate content signals scraping opportunities and makes your site appear lower quality. Produce original content and limit copies.

18. Use Trusted Themes/Plugins

Downloading random themes/plugins from anywhere opens you up to compromised code injected with malware.

Stick to respected repositories like WordPress.org for themes and plugins where submissions are vetted. Avoid nulled software or pirated options which are high risk.

Also research the author and reviews to identify reputable plugins from trustworthy developers.

19. Limit Admin Users

Reduce the number of users with admin access to only those who legitimately need it. Avoid assigning the administrator role freely.

Create lower permission roles for general users like Editor, Author, or Contributor. They can view/update some content but without full privileges.

The fewer admins, the lower chance of a compromised account taking over everything. Revoke admin permissions whenever possible by using the lowest role needed.

20. Remove Default Themes/Plugins

WordPress installs with default themes (Twenty*) and several starter plugins activated by default.

These commonly targeted defaults provide attack vectors if left intact. Eliminate what you don’t need:

  • Delete unused default themes.
  • Deactivate and remove default plugins.

Less you have active, the smaller your attack surface.

21. Protect Uploads Folder

The wp-content/uploads folder contains all user-uploaded files. This is regularly targeted for injection of malware or executable scripts.

Lock it down by:

  • Disabling PHP execution in uploads.
  • Restricting file upload types.
  • Scanning uploaded files for malware.

Also use a plugin like Secure Copy Protection to add .htaccess hardening that blocks PHP/JS execution in uploads.

22. Login Screen Customization

Keep login and admin URLs obscure by customizing the login screen:

  • Change the login URL.
  • Customize the login page design.

This makes it harder for hackers to find and target your login area.

23. Careful With Contributor Accounts

Allowing contributor users still enables them to potentially compromise your site. Limit what contributors can do:

  • Restrict file uploads.
  • Monitor content closely.
  • Limit access to sensitive settings.

Contributors should focus just on content, with site management done solely by admins. Review their permissions carefully.

24. Update Everything

Running outdated software is asking for trouble security wise.

Stay on top of updates:

  • WordPress core.
  • Plugins.
  • Themes.

Subscribe to update notifications from your host and enable auto-updates where possible. Also regularly check manually for anything to patch.

25. Disable Directory Listing

Directory listing provides a full index of all files in folders like wp-includes and wp-content. This reveals sensitive paths and file names better kept hidden.

Disable directory listing in .htaccess:

Options -Indexes

Also ask your host to disable it at the server level for enhanced security against snooping.

26. Manage User Sessions

Keep user sessions as short as possible and frequently rotate session IDs.

Add this to wp-config.php:

define('AUTH_COOKIE_LIFETIME', 172800); // 48 hours
define('AUTH_REFRESH', true);
define('AUTH_SALT', 'complex phrase');

This invalidates sessions after 48 hours and assigns a unique salt per site for stronger session IDs.

Also consider using a plugin like Manage WP Worker for more granular user session management.

27. Content Security Policy

A Content Security Policy (CSP) restricts what resources browsers can load from your site. This mitigates cross-site scripting attacks.

The official CSP plugin configures a strict policy disabling unsafe practices like:

  • Inline JavaScript.
  • Eval().
  • Loading resources from untrusted sources.

This limits external scripts and code execution to only authorized sources you define.

28. Regular Scans

Run in-depth security scans monthly or more often to detect vulnerabilities or malicious code. This identifies issues to address proactively instead of after being hacked.

  • Use a plugin like Wordfence or Sucuri SiteCheck.
  • Review scan reports carefully.
  • Fix any problems found immediately and rescan regularly. Don’t ignore warnings.

29. Secure Database Backups

Backing up your WordPress database is critical. But also be sure to secure backups properly:

  • Encrypt backups.
  • Store backups offsite.
  • Regularly test restoration.

This keeps your data, users, and settings safe if compromised.

30. Disable File Editing

As mentioned earlier, the file editor in WordPress enables editing plugins and themes right from the admin screen. This is very dangerous from a security perspective.

Plugins like WP Force Disable File Editor do more than just removing access – they completely disable the editor functions across WordPress.

For maximum safety, force disable the file editor entirely across all areas of WordPress.

31. Limit PHP Memory

The PHP memory limit determines how much data a script can use. Too high, and it can enable DDoS attacks and system crashes.

Lower the memory limit in wp-config.php:

define( 'WP_MEMORY_LIMIT', '64M' );

Also work with your host to set server-level PHP memory ceilings appropriate for your site.

32. Disable Pingbacks

Pingbacks allow notifications between blogs when linked. This can lead to amplification attacks

Leave a Reply

Your email address will not be published. Required fields are marked *