Ways to harden your WordPress website without using bulky plugins

You can add security plugins to your website, but if you don’t know exactly what they’re doing, not only can you silently break things, but you can slow down your site with a lot of extra code. They’re great, but it’s not like there isn’t risk in blindly activating any plugin. I develop plugins and try to predict how things can go wrong, so I know just how bewildering the number of things that can go wrong feels. When I can simplify things on my own sites, I always go that route.

I recently decided to stop using a security plugin because I’ve implemented security measures of my own, and my server handles SSL redirection. I love the Really Simple SSL plugin but didn’t need it in this particular instance. Really Simple SSL had a couple nice features I decided to just hardcode into my functions.php file. Here are a couple of them:

Disallow ‘admin’ Usernames

Wordpress includes a quick and easy filter hook, called “illegal_user_logins”, for adding disallowed WordPress usernames. You’ll want to disable ‘admin’ and ‘administrator,’ and any other predictable usernames for your setup (such as your domain name and nickname). If you’re already using these usernames, you’ll want to change them in your MySQL database _users table first. This hook defines elements of an array. The following code adds an ‘admin’ element to that array:

/**
 * Make the 'admin' login inaccessible to new users
 *
 * @param array $illegal_logins
 * @return array
 */
function make_admin_user_login_illegal( $illegal_logins ) {

    $illegal_logins[] = 'admin';
    $illegal_logins[] = 'administrator';
    return $illegal_logins;

}
add_filter( 'illegal_user_logins', 'make_admin_user_login_illegal', 9, 3 );

Restrict User Enumeration

Hackers can type in your URL followed by /?author=1 (because the admin is usually user #1) and find out your username, which gives them half the information they need to force a hack. They can do this on any other user, starting with the number 2, your second registered WordPress user. Make usernames hard to guess, and keep them from finding them so easily with this PHP code, taken from Really Simple SSL:

/**
 * Prevent User Enumeration
 *
 * @return void
 */
function check_user_enumeration() {
    if ( ! is_user_logged_in() && isset( $_REQUEST['author'] ) ) {
        if ( preg_match( '/\\d/', $_REQUEST['author'] ) > 0 ) {
            wp_die( sprintf( 'Forbidden - number in author name not allowed = %s', esc_html( $_REQUEST['author'] ) ) );
        }
    }
}
add_action( 'init', 'check_user_enumeration' );

.HTACCESS

Here are lines which can be added to your site .htaccess file (in the root of the WP installation; in the same folder as the wp-includes and wp-admin folders). If anything is site-breaking, it can either be removed, or simply commented out (ignored) by pre-fixing the line with a # (hash symbol, hash tag). As you can see below, comments are started with a hash.


# To remove HSTS. Keep the line, but set max-age to zero. Or "max-age=0"
Header set Strict-Transport-Security "max-age=31536000" env=HTTPS
Header always set X-Content-Type-Options "nosniff"
Header always set Expect-CT "max-age=7776000, enforce"
# X-XSS-Protection is used to configure the built in reflective XSS protection
Header always set X-XSS-Protection "1; mode=block"
# A Referrer-Policy should be set by all websites
Header always set Referrer-Policy: "no-referrer-when-downgrade"
# Content Security Policy is an effective measure to protect your site from XSS attacks
Header always set Content-Security-Policy "upgrade-insecure-requests;"
# X-Frame-Options tells the browser whether you want to allow your site to be framed or not: NOT!
Header always set X-Frame-Options "SAMEORIGIN"

Header set Permissions-Policy "interest-cohort=()"

# Deny access to your debug.log files (if they exist)

   Require all denied


# Block WordPress xmlrpc.php requests

order deny,allow
deny from all

(advertisement)