WordPress is among the most widely used CMS in the world. This popularity has also lead to a number of issues within wordpress. We will look at how to harden wordpress using four elements , together or either one depending on level of hardening required. The 4 methods include:
- Hardening via htaccess
- Hardening via patching the theme
- Hardening using plugins
- Hardcore Hardening in wp-config
Before we start a default wordpress install would have a screaming fingerprint as below:
Hardening via htaccess
The htaccess file enables us to modify some of the “policies” or “rules” based on a server’s default configuration. Please note that not all servers allow override of rules via htaccess. If this is the case you may consult with your hosting provider. Htaccess is mostly used in apache servers and doesn’t work on minimal ones like nginx.
Today we will add a few rules to atleast secure wordpress from common fingerprint and security issues.
Disable Directory Listing
This is a really small but really key thing as it shows the files hosted on your server. Some of the key folders affected by this include:
wp-includes/
wp-content/uploads/
in htaccess we can add a line as below to protect against listing of files in directories. This will return a 403 – Forbidden error.
Options -Indexes
Protect Include Files
This would help protect the include files from direct access as most of them have issues like Full Path Disclosure on rss-functions.php as an example. To avoid this direct access would attempt to force a forbidden error and redirect the user to the last known address. This directive is as below in htaccess. (Please note that this would be in the rewrite section).
RewriteRule ^wp-admin/includes/ – [F,L]
RewriteRule !^wp-includes/ – [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ – [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php – [F,L]
RewriteRule ^wp-includes/theme-compat/ – [F,L]
Protect from Script Injection
This will help us stop anyone from embedding script tags , register a global variable or modify a request variable via the URL and return them to the homepage with a 403 – forbidden error.
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})
RewriteRule . /index.php [L]
Limit Access to XMLRPC interface
This directive will aid in limiting access to the XMLRPC interface from specific whitelisted IP addresses or none at all. currently its limited to localhost in the directive below. The reason for doing this is because there are a number of attacks against the interface, see an example here.
<Files xmlrpc.php>
order deny,allow
deny from all
allow from 127.0.0.1
</Files>
Prevent sensitive files from direct access
There are some files on the server that would pose a risk if exposed and would give information that would be valuable to an attacker. These files are as below and we will block direct access to them.
- wp-config.php – contains configuration, goes without saying it needs to be kept from prying eyes
- wp-admin/install.php – This file gives the wordpress version in the source code when directly accessed. Shouldn’t be needed after a successful install but just incase deny access to it till the day you need it.
- htaccess – it contains our rules therefore we must protect it.
- all txt,md,html and xml files – the files with these extensions are informational but have alot of versioning information we can block access to them via the web.
- wp-links-opml.php – This file dumps the wordpress generator in XML format and can be used for accurate fingerprinting.
- wp-cron.php – if wordpress cron jobs are not disabled , this file can be used to load the server with requests.
- wp-signup.php – This file has a redirect that would make it known any rewritten path other than wp-admin and would expose backend protection , if registration is disabled the directive in regard to this file should be put in place.
- wp-emoji-loader.min.js – The md5 hash of this file is used by many scanners e.g. wpscan to fingerprint various wordpress versions in its advanced fingerprinting module.
The directives to block the above are as below :
<files wp-config.php>
order allow,deny
deny from all
satisfy all
</files>
<files install.php>
order allow,deny
deny from all
satisfy all
</files>
<files ~ “^.*\.([Hh][Tt][Aa])”>
order allow,deny
deny from all
satisfy all
</files>
<Files ~ “\.(txt|html|md|xml)$”>
order allow,deny
deny from all
satisfy all
</Files>
<files wp-links-opml.php>
order allow,deny
deny from all
satisfy all
</files>
<files wp-cron.php>
order allow,deny
deny from all
satisfy all
</files>
<files wp-signup.php>
order allow,deny
deny from all
satisfy all
</files>
<files wp-emoji-loader.min.js>
order allow,deny
deny from all
satisfy all
</files>
Add some secure headers
It’s also good practice to add some secure headers to your responses , however please note some like CSP and X-Frame options might hinder loading of external scripts and may break styling of your site if not well written. Below however are 2 rules that will not have that effect.
Header always set x-xss-protection “1; mode=block”
Header always set X-Content-Type-Options “nosniff”