Securing WordPress Login Using HTTP Authentication

S

Having spent some considerable time and effort cleaning this site after it had been hacked I was determined to make it as secure as I possibly could in an attempt to prevent it happening again.

This is a WordPress site running on an Apache server so one of the numerous measures I implemented was to use HTTP Authentication to password-protect the wp-login.php file.

Let’s assume the site’s URL is mydomain.com and its document root is set to /home/content/public/. The wp-login.php file is located in the document root along with other WordPress files and folders. There may also be an .htaccess file depending on how WordPress has been configured.

The document root of mydomain.com mapped to the public directory

The document root of mydomain.com mapped to the public directory

 

 

The first step in protecting wp-login.php using HTTP Authentication is to create a file that will contain an authorised username and encrypted password. The file name — for instance .htpassword — should begin with a period.

It’s good practice to place this file outside of the document root. Here, it’s located one level above the document root in the /home/content/ directory.

The .htpassword file located one level above the document root of mydomain.com

The .htpassword file located one level above the document root of mydomain.com

 

 

An online password generator can be used to generate encrypted passwords. For example, using MD5 encryption the username and password jsmith secret would generate something similar to jsmith:$apr1$aVIXtDhj$yUk0MKtlR77CVo97dyBF9/. This entire string should be copied into the .htpassword file.

Online htpasswrd generator at aspirine.org

Online htpasswrd generator at aspirine.org

 

 

The next step is to add the following directive to the .htaccess file in the directory where wp-login.php is located: in this case, the site’s document root.

# Protect wp-login.php
<Files wp-login.php>
	AuthType Basic
	AuthName "Message to display"
	AuthGroupFile /dev/null
	AuthUserFile /home/content/.htpassword
	Require user jsmith
</Files>

The File directive in /home/content/public/.htaccess

The AuthName directive on line 4 defines what the Apache documentation describes as the Realm.

The AuthName directive sets the Realm to be used in the authentication. The realm serves two major functions. First, the client often presents this information to the user as part of the password dialog box. Second, it is used by the client to determine what password to send for a given authenticated area.

In this example it’s used merely to display a message to the user. On line 6 the AuthUserFile directive contains the absolute path to the .htpassword file and on line 7 the Require directive defines the authorised user.

Now, whenever an attempt is made to login to the back-end of the WordPress install using mydomain.com/wp-login.php or mydomain.com/wp-admin the HTTP Authentication prompt is displayed.

The HTTP Authentication prompt

The HTTP Authentication prompt for mydomain.com

 

 

When creating sub domains there is one minor drawback of using this method that is not so obvious at first.

Consider a shared hosting environment where the document root of the primary domain — as in our example — is mapped to the root directory. The document root of any sub domain of the primary domain has to be mapped to a sub directory within the root directory.

For example, the document root of the primary domain mydomain.com is mapped to the public directory. If I want to use the sub domain sub.mydomain.com its document root must be mapped to (say) the sub-domain directory within the public directory.

The document root of sub.mydomain.com mapped to the sub-domain directory

The document root of sub.mydomain.com mapped to the sub-domain directory

 

 

WordPress is installed in the sub-domain directory but HTTP Authentication is not used to password-protect the wp-login.php file. However, attempting to login to the back-end of the WordPress install in the sub-domain directory using sub.mydomain.com/wp-login.php or sub.mydomain.com/wp-admin requires HTTP authentication.

The reason is that the Files directive in the /home/content/public/.htaccess file not only password-protects the /home/content/public/wp-login.php file but all instances of wp-login.php in all sub directories. Consequently, accessing the /home/content/public/sub-domain/wp-login.php file requires HTTP Authentication even though it has not been explicitly set in the /home/content/public/sub-domain/.htaccess file.

While this may not necessarily be an issue, protecting /home/content/public/sub-domain/wp-login.php using a different authorised user or even choosing not to password-protect it requires changes to the /home/content/public/.htaccess file.

# Protect wp-login.php
<Files wp-login.php>
	<If "%{SERVER_NAME} =~ /^(www\.|)mydomain\.com$/">	#Matches 'mydomain.com' or 'www.mydomain.com' only
		AuthType Basic
		AuthName "Message to display"
		AuthGroupFile /dev/null
		AuthUserFile /home/content/.htpassword
		Require user jsmith
	</If>
</Files>

The amended .htaccess file requiring HTTP Authentication for mydomain.com/wp-login.php only

The original /home/content/public/.htaccess file has been amended to include a conditional If directive on line 3 which checks the value of the SERVER_NAME variable and only requires HTTP Authentication if it’s equal to mydomain.com or www.mydomain.com. Consequently, sub.mydomain.com/wp-login.php is no longer protected.

# Protect wp-login.php
<Files wp-login.php>
	<If "%{SERVER_NAME} =~ /^(www\.|)mydomain\.com$/">	#Matches 'mydomain.com' or 'www.mydomain.com' only
		AuthType Basic
		AuthName "Message to display"
		AuthGroupFile /dev/null
		AuthUserFile /home/content/.htpassword
		Require user jsmith
	</If>
	<If "%{SERVER_NAME} == 'sub.mydomain.com'">
		AuthType Basic
		AuthName "Message to display"
		AuthGroupFile /dev/null
		AuthUserFile /home/content/.htpassword
		Require user tjones
	</If>
</Files>

Amended .htaccess file requiring separate HTTP Authentication for sub.mydomain.com/wp-login.php

To password-protect sub.mydomain.com/wp-login.php another conditional block can be included that will execute HTTP Authentication if the SERVER_NAME variable equals sub.mydomain.com. Here the authorised user — tjones — and password are different to the one required for mydomain.com but both use the same .htpassword file.

About the author

A native Brit exiled in Japan, Steve spends too much of his time struggling with the Japanese language, dreaming of fish & chips and writing the occasional blog post he hopes others will find helpful.

5 responses

Leave a Reply to Sadi Cancel reply

5 Comments

  • We’ve been hacked on a daily basis. I hope your article helps this time. I made it. Tested it. Works. Now time will tell. Thank, Author. Keep the good content flowing.

    • @Sadi,

      Remove or comment-out the following code block in the .htaccess file in the directory where wp-login.php is located. This is usually the site’s document root.

      # Protect wp-login.php
      <Files wp-login.php>
      	AuthType Basic
      	AuthName "Message to display"
      	AuthGroupFile /dev/null
      	AuthUserFile /home/content/.htpassword
      	Require user jsmith
      </Files>
      

      Regards, Steve.

  • Thank you Steve for taking time to share this post. It had not tried such approach for securing wp-login.php so far. I will give it a try.

    Cheers

Steve

Recent Comments

Recent Posts