Access Control for Apache 2.4 (and 2.2)

Category: Blog • Posted by Jeff Starr • Updated:

Throughout the book, I explain various techniques for controlling access to web pages. For example, if you are getting hit with an attack from a specific range of IP addresses, you can add directives to block them based on the host address or other variables. It is a common technique that I’ve discussed numerous times. With Apache 2.4, there are changes to the directives that are used for access control. This tutorial explains the changes and then shares some examples to help you implement the best solution for your site.

Note: this topic is covered in the book on page 147, “Allow/Deny directives for Apache 2.4+” (in Chapter 7: Tighten Security).

Changes in Apache 2.4

Summary:

Apache 2.2 uses the authz_host_module to control access using directives like Deny, Allow, and Order.

Apache 2.4 uses also the authz_host_module for access control, but also uses the authz_core_module, which provides the new Require directive.

So basically, the rules to control access are different depending on your version of Apache. To help with this, I’ve provided numerous examples below.

Code Examples

Here are some examples that compare the different syntax required depending on your version of Apache.

Important! Do not use 2.2 and 2.4 directives on the same server; it may cause issues and/or errors. A workaround for this is to use Conditional Directives, as explained below.

Deny all requests

# DENY ALL REQUESTS

# Apache 2.2
Order deny,allow
Deny from all

# Apache 2.4+
Require all denied

Allow all requests

# ALLOW ALL REQUESTS

# Apache 2.2
Order allow,deny
Allow from all

# Apache 2.4+
Require all granted

Deny access based on host name

# DENY ACCESS TO EXAMPLE.COM

# Apache 2.2
Order Allow,Deny
Allow from all
Deny from example.com

# Apache 2.4+
<RequireAll>
    Require all granted
    Require not host example.com
</RequireAll>

Notice that <RequireAll> and Require all granted are required when doing anything more than either Require all granted or Require all denied (as shown in the above examples). Here a couple more examples to further illustrate the concept using Require/All.

Deny access based on IP address

# DENY ACCESS TO IP ADDRESS

# Apache 2.2
Order Allow,Deny
Allow from all
Deny from 111.111.111.111
Deny from 222.222.222.222
Deny from 123.123.123.123

# Apache 2.4+
<RequireAll>
    Require all granted
    Require not ip 111.111.111.111
    Require not ip 222.222.222.222
    Require not ip 123.123.123.123
</RequireAll>

Deny access to specific file

# DENY ACCESS TO FILE

# Apache 2.2
<Files ~ "example\.txt">
	Order Allow,Deny
	Allow from all
	Deny from 123.123.123.123
</Files>

# Apache 2.4+
<Files ~ "example\.txt">
	<RequireAll>
		Require all granted
		Require not ip 123.123.123.123
	</RequireAll>
</Files>

Reminder: Do not use both 2.2 and 2.4 directives on the same server. Doing so may cause errors. Use only the code that applies to your version of Apache. Or, if you want to create a modular, plug-n-play snippet that can be added to any Apache version 2.2 or 2.4+, check out the conditional directives technique in the next section.

Example: Conditional Directives

In some cases, you may not know which version of Apache you are using. In such case, the following conditional directives should give you a better idea. You can use the following code on any Apache server version 2.2 or 2.4+.

# Apache 2.2
<IfModule !authz_core_module>
	Order Deny,Allow
	Deny from all
	Allow from 123.123.123.123
</IfModule>

# Apache 2.4+
<IfModule authz_core_module>
	<RequireAll>
		Require ip 123.123.123.123
	</RequireAll>
</IfModule>

When included via .htaccess or Apache configuration file, this code will detect the correct version of Apache and use the proper directives for access control. Here’s how it works:

If the server is Apache 2.2 then we know that authz_core_module does not exist. So any directives included inside of the first <IfModule> container will be executed only on Apache 2.2.

Or if the server is Apache 2.4+ we know that authz_core_module exists. So any directives included inside of the second <IfModule> container will be executed only on Apache 2.4 and better.

Bonus! Alternate syntax

Here is an alternate way of writing conditional rules for Apache access control:

<Files "*">
	
	<IfModule mod_version.c>
		<IfVersion < 2.4>
			Order Deny,Allow
			Deny from All
		</IfVersion>
		<IfVersion >= 2.4>
			Require all denied
		</IfVersion>
	</IfModule>
	
	<IfModule !mod_version.c>
		<IfModule !mod_authz_core.c>
			Order Deny,Allow
			Deny from All
		</IfModule>
		<IfModule mod_authz_core.c>
			Require all denied
		</IfModule>
	</IfModule>
	
</Files>

Of course, these are just examples to show how to implement the correct access-control directives. You will want to consult the Apache docs and modify the code to suit your specific needs.