How to secure a WordPress site with .htaccess

In this tutorial, I will teach you how to secure a WordPress site with .htaccess through the prevention of HTTP use, XSS, content sniffing, directory browsing, hotlinking, access to some files, and author scans.

Please note that this tutorial is part of a series to help secure a WordPress blog. Some of these tips might not apply depending on the hosting environment. The following topics are covered:

What is .htaccess?

.htaccess (hypertext access) is a type of file available to websites served by Apache allowing website owners to configure directory access. If you have direct access to Apache’s configuration, use that instead. Apache’s configuration has a “.conf” extension and is found in the “etc” folder.

To help secure a WordPress site with .htaccess, a few lines can be added to the file, which is located in the root folder of the WordPress installation. If one cannot be found, the first step is to create new file called “.htaccess” in the root folder of the WordPress installation.

Deny access to .htaccess

Not only should you deny access to .htaccess, all files starting with a dot should be restricted:

<FilesMatch "^\.">
Order allow,deny
Deny from all
</FilesMatch>

Restrict access to wp-login.php, xmlrpc.php, wp-config.php and php.ini

The wp-login.php file is the login page of the WordPress installation.

XML-RPC is a protocol based on XML (extensible markup language) and is generally used for remote procedure calls (RPC). Please note that restricting access to xmlrpc.php may cause issues with the Jetpack plugin.

The wp-config.php file contains sensitive database information.

The php.ini file is the website’s PHP configuration.

To restrict access to these files, deny all IPs except for your own. Copy and paste the following in your .htaccess file and replace “000.00.000.000” with your own IP address. A quick Google search of “My IP” will yield your IP address.

<FilesMatch "wp-login\.php|xmlrpc\.php|wp-config\.php|php\.ini">
order deny, allow
deny from all
allow from 000.00.000.000
</FilesMatch>

Force browsers to use HTTPS

Before proceeding, your website needs to be setup with a valid SSL certificate.

Even though some hosts allow you to set HTTPS redirect through the cPanel, it is important to set the HSTS (HTTP Strict Transport Security) header in the .htaccess file to further force browsers to use HTTPS. To do so, include the following line:

Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

Google recommends a maximum age of two years.

As using this header alone leaves a door open during the initial connection, you may submit your website to the HSTS preload list to close this door on most major browsers.

Add XSS protection

The XSS header can prevent some (but not all) cross-site scripting, which is when an attacker injects web pages with client-side scripts.

Header set X-XSS-Protection "1; mode=block"

The number 1 signifies that the XSS filter is enabled and the block mode signifies that the browser will prevent the page from rendering should an attack be detected.

Prevent content sniffing

Content sniffing, otherwise known as MIME (multipurpose internet mail extensions) sniffing, is the browsers examination practices to determine the content type (or MIME type) without the use of the Content-Type header and is enabled by default. Enabling it may help the browser in reading files as they are intended but it might also put users at risk should they be able to upload and download files.

The X-Content-Type-Options header is only supported by a few browsers.

Header set X-Content-Type-Options nosniff

Disable directory browsing

The address of a folder/directory without an index file yields a list of all files contained within that folder, otherwise known as a directory listing.

Directory listing example to be disabled with the .htaccess file for WordPress security.

Disabling directory listings makes it more difficult for a hacker to scan a website to find vulnerable files.

Options All -Indexes

Disable hotlinking

Hotlinking is when a website displays an image uploaded on different server. It is important to disable hotlinking as every time an image is loaded, it uses some of the servers resources.

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?example.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?google.com [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ http://example.jpg [NC,R,L]

Replace “example.com” with your domain name and http://example.jpg with the URL of the image you would like hotlinkers to get when they try to display one of your images.

The fourth line declares that Google may use the website’s images. This rule may be taken out by removing the line. One can also duplicate the line to replace google.com with yahoo.com, for example:

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?example.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?google.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yahoo.com [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ http://example.jpg [NC,R,L]

Block author scans

Author scans are when bots phish for user IDs and usernames by scanning author links to use in a brute force attack. A brute force attack is when an attacker tries to obtain login credentials by repeatedly trying different combinations.

https://example.com/?author=1

The link above is an example of a URL a bot would try to access. The user ID is 1, which represents “Admin”.

Before setting the rules in the .htaccess file, ensure that your website is not using query-string URLs as highlighted above. To do so, log into your WordPress installation and navigate to “Permalinks” under “Settings”. Select any common setting but “Plain”.

Permalink settings page

It is also important to ensure that the WordPress theme is does not display usernames. A few places to look for usernames include:

  • Single posts;
  • Author page/archive view; and
  • Comments

One could either remove their use in the WordPress theme or change the user’s display name. To do the latter, click on “All users” under “Users” and “Edit” under the user’s username.

Click "All users" > "Users" and "Edit" under the user's username.

On the profile page, scroll down to “Name” and change “Display name publicly as” to anything but the user’s username. Scroll to the bottom of the page and click “Update Profile”.

Scroll to "Name" and change "Display name publicly as" to anything but the user's username.

In your .htaccess file, include the following lines:

<IfModule mod_rewrite.c>
RewriteCond %{QUERY_STRING} ^author=([0-9]*) [NC]
RewriteRule .* - [F]
</IfModule>

The lines above block scans performed by bots and inform the bot that the website is blocking such scans by serving a 403 error.

Disable PHP execution

An attacker can inject a website with an unwanted file to serve as a back-door. For example, they could upload a PHP file to a website through a form to later execute. The PHP code contained within could potentially query the database for information and display it to the attacker.

To disable PHP execution, create an .htaccess file in the following two folders:

  • /wp-includes
  • /wp-content/uploads

Place the following lines in both .htaccess files:

<Files *.php>
Order allow,deny
Deny from all
allow from 000.00.000.000
</Files>

Replace 000.00.000.000 with your own IP address to preserve the ability to add/edit pages and posts.

Conclusion

In summary, the .htaccess file allows you to deny access to certain files, redirect users to HTTPS, disable PHP execution and add XSS protection. It also allows you to prevent content sniffing, disable directory browsing, disable hotlinking and block author scans.

If you know of any steps one could take to secure a WordPress site with .htaccess, please let me know in the comments down below!

Leave a Reply

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

Back to top