WordPress Security Checklist

NB: Do not copy-paste into an existing WordPress installation without reviewing and editing accordingly!

This is a living document, currently in more of a draft state. Untested snippets are marked as such.

Notes

  1.  Always place htaccess rules outside # BEGIN WordPress and # END WordPress
  2. The .htaccess rules below are meant for Apache version ≥ 2.3

Block “Empty User Agent String” Website Visits

/.htaccess:

RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} ^-?$
# allow request from server Cron; mind the dollar sign after the IP:
RewriteCond %{REMOTE_ADDR} !^YOUR_SERVER_IP_ADDRESS$
RewriteRule ^ - [F,L]

chmod folders 755; files 644

Linux CLI:

find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;

chmod themes’ functions.php to 600 (prevents code injection, malware, etc)

Redirect all traffic to https

https://serverguy.com/servers/redirect-http-to-https/

WP-Config Obfuscation

1) Move wp-config outside /public_html/ (a.k.a. one level higher)
–or–

2) Move all wp-config content to a custom file and require_once() it back in wp-config

Deny all access for wp-config.php (when present in root folder)

/.htaccess:

<files wp-config.php>
order allow,deny
deny from all
</files>

Give /wp-content/ its own domain

Disable ?author=1 queries

/.htaccess:

# Disable ?author=1 queries
RewriteEngine On
RewriteCond %{QUERY_STRING} ^author= [NC]
RewriteRule .* - [F,L]
RewriteRule ^author/ - [F,L]

BasicAuth /wp-admin/

/wp-admin/.htaccess:

AuthType Basic
AuthName "Password Protected Area"
AuthUserFile /home/<user>/<website>/wp-admin/.htpasswd
Require valid-user

htpasswd:

http://www.htaccesstools.com/htpasswd-generator/

Block access to /wp-admin/admin-ajax.php

/.htaccess:

<Files admin-ajax.php>
Order allow,deny
Allow from all
Satisfy any
</Files>

Remove directory listing

/.htaccess:

Options -Indexes

Kill PHP Execution in /Uploads/ and /WP-Includes/

/wp-content/uploads/.htaccess:
/wp-includes/.htaccess:

<FilesMatch "\.ph(?:p[345]?|t|tml)$">
Order Deny,Allow
Deny from all
</FilesMatch>

Disable dashboard file editing in wp-config

## Disable Editing in Dashboard
define('DISALLOW_FILE_EDIT', true);

Hide wp-admin

Write your own logic or use WPS Hide Login.

12. limit-login-attempts

Hiding the admin page makes this measure unnecessary.

Block Image Hotlinking With a 403 Code

/!\ not tested

RewriteEngine on
# Allow my domain
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?mydomain.com [NC]
# File types to be blocked
RewriteRule \.(jpg|jpeg|png|gif)$ - [NC,F,L]

13. Disable public access to /wp-content/debug.log

/.htaccess

<Files "debug.log">
Require all denied
</Files>

WP-Config.php Settings:

// Disable All Automatic Updates (except for core)

define( 'AUTOMATIC_UPDATER_DISABLED', true );

* Completely disables the auto-updater mechanism.
Src: https://make.wordpress.org/core/2013/10/25/the-definitive-guide-to-disabling-auto-updates-in-wordpress-3-7/

Disable Automatic Updates Except For Core

// Disable plugin and theme update and installation
define( 'DISALLOW_FILE_MODS', true );

// Limit auto-Updates to Core only
define( 'WP_AUTO_UPDATE_CORE', 'minor' );

Did this solve your issue?