Securing Apache

113

Author: Mike Peters

A few weeks ago I wrote about installing Apache in a chroot jail, a technique that can reduce the
potential damage from a compromise of your server by preventing an attacker
from gaining access to your server’s root filesystem. In this article I will
look at how to configure the Apache server environment to protect your Web site.

The wisest policy is to run Apache with only the modules you need. That means you should compile and load only a minimal number of modules. You can do
this by passing options to configure:

./configure --enable-mods-shared="access log_config dir mime auth auth-digest"
--enable-so

If you are using Apache 1.3.xx, you can edit the src/Configuration file before
running make, and comment out the AddModule lines corresponding to the
modules you don’t need.

Two modules you really don’t want to include are mod_autoindex, which
provides automatic directory indexing, and mod_info, which can be used to leak
information about the server’s configuration.

Once you have run ./configure and make, su to root and run

umask 022
make install
chown -R root:sys /usr/local/apache

to install the binary and set the necessary permissions.

After compiling and installing Apache you should set up a group
and user specifically for the Apache binary, with the commands

# groupadd apache
# useradd -c "Apache Server" -d /dev/null -g apache -s /bin/false apache

This creates a regular user apache and the apache
group. While Apache runs as the unprivileged nobody user by default, user nobody
may be used by many processes, and if it is compromised an intruder can gain access to all
processes on your system running under that UID.

Configuration

Most security violations are the result of bad configuration. You should configure
your server to run with the minimum level of authorization required for
clients to work effectively. For example, if you need to provide
access only to certain hosts, configure Apache to listen to requests from only
those hosts by editing your httpd.conf file. The rest of this article refers to changes you can make in httpd.conf.

In recent versions of Apache, the Listen directive is required (or Apache
will fail upon startup) to tell Apache which port to listen on. If you only
need to serve a small number of hosts, you can also use this directive to specify the
IP addresses to which Apache should listen:

Listen 192.168.1.11:80
Listen 192.168.1.12:80

Otherwise, just use Listen 80, or whichever port you want Apache to
listen to. Remove any AddModule directives you don’t need. The configuration file should also contain the following, and I’ll explain each line in turn below:

User apache
Group apache

HostNameLookups Off

ServerAdmin admin@myserver.com

ServerRoot "/usr/local/apache"
DocumentRoot "/var/www/htdocs"

UserDir disabled root

ServerTokens Prod
ServerSignature Off

The User and Group directives ensure that Apache runs as the specific user
and group you configured earlier.

Turning HostNameLookups off provides better performance, as this
ensures Apache will not try to resolve any IP addresses. It also
slightly decreases the possibility of spoofing attacks.

ServerAdmin should be set to a valid email address which someone checks regularly, as this is the contact address which will be given in any error messages presented to the client.

The ServerRoot directive tell the server where it is installed and therefore
where to find configuration files. DocumentRoot is where the Web pages of your
site are stored

UserDir allows users to host personal sites in a directory under their /home
directory. This should always be disabled for root, as advised by the Apache team.

By default Apache will give out information about its version and
configuration. Using ServerTokens Prod will only give out the string “Apache”; the less information someone can get about your server, the more secure it is likely to be.
In versions of Apache prior to 2.0.44, ServerSignature could leak the version
of your server, so we turn that off. In more recent versions this is controlled
by the ServerTokens directive.

Files and directories

We should now set up options for the various directories on our server.

<Directory / >
 Options None
 AllowOverride None
 Order deny,allow
 Deny from all
</Directory>

Our first entry sets up the most restrictive permissions possible for our /
(root) directory. This sets a default policy to deny access to all directories. We
will allow access to specific directories below. Options None makes sure that all
directives such as FollowSymLinks and any others which may be enabled by default
are switched off. AllowOverride None ensures that users cannot use a .htaccess
file to override the default permissions set in the httpd.conf file.

If for some reason you want to use a .htaccess file to override settings in
httpd.conf, simply use the AllowOverride directive
within a <Directory> block. You should be careful about just what you
allow users to override, however. The directive types available for AllowOverride include:

Indexes — allow users to specify indexing options for the directory
AuthConfig — allow users to set authorization directives (i.e., require a
username and password)
Limit — specify host access with Allow and Deny directives

For example, AllowOverride AuthConfig Limit allows a user
to place directives in a .htaccess file to require a password to access any files hosted in the directory, and Limit allows the user to specify which hosts can gain access to the directory through the Allow and Deny directives. These options
can be set by the user regardless of any site-wide options you have set in httpd.conf.

Although we want to allow .htaccess files in some directories we
should never let clients download and read these files. We can prevent this
with the File directive:

<Files ~ "^/.ht">
    Order allow,deny
    Deny from all
</Files>

This prevents users from accessing any files on the server whose names
begin with .ht.

The Allow and Deny directives within a <File> or <Directory> block can
be used to limit access to certain files or directories to certain specified
hosts or networks. The order in which the directives are applied is designated
by the Order directive. You can use as many lines as you need, as the
example below illustrates.

<Directory "/var/www/htdocs/restricted" >
 # Deny all access by default by applying the deny directive first
 Order deny,allow
 # Allow access to the local machine
 Allow from 127.0.0.1
 # Allow access to a single remote host
 Allow from 192.168.2.7
 # Allow access to a local network
 Allow from 192.168.1.
 # Deny from everyone else
 Deny from all
</Directory>

User authentication

Apache allows us to require user authentication for access to certain
directories. The authentication method can be one of two types, Basic or
Digest.

Basic authentication

To set up a directory that requires a user to supply a username and
password we would use something like the following in our httpd.conf file:

<Directory "/var/www/htdocs/protected" >
 Order deny,allow
 Deny from all
 Allow from 192.168.1.
 AuthName "Private Information"
 AuthType Basic
 AuthUserFile /usr/local/apache/conf/passwd
 AuthGroupFile /usr/local/apache/conf/groups
 require group <group-name>
</Directory>

Firstly we have denied access to all users but those on our internal
network to the directory /var/www/htdocs/protected. To require a password we
use the AuthType Basic directive. Our password file is
/usr/local/apache/conf/passwd, as specified by the AuthUserFile directive and,
similarly, we specify a group file. The last line require group <group-name>
means that a user must be a member of <group-name> in order to be
allowed access to the directory.

Of course, for this to work, we must set up our password and group files.
For the group file simply create a file, /usr/local/apache/conf/groups,
containing the line:

group-name: user1 user2

You can specify as many groups as you wish on separate lines. List users
separated by a space.

Next we create the password file with the command
htpasswd -cm /usr/local/apache/conf/passwd user1. This will
prompt for a password and
create a user with name user1 in the file /usr/local/apache/conf/passwd.
The c option will create the file if it doesn’t exist, and the m option will MD5 hash
the password (SHA1 and crypt options are also available, but SHA1 does not work
with some Apache versions). Subsequent users can be added using
htpasswd -m /usr/local/apache/conf/passwd user1.

If you do not want to use groups you could use require valid-user user1
user2
in order to only allow access to certain users.

The disadvantage of Basic Authentication is that passwords are sent as
plain text from the client to the server, meaning that it is simple for
a malicious user with access to the network can obtain the password using a
network traffic analyzer. Digest Authentication tries to prevent this.

Digest Authentication

In digest authentication the password is never transmitted across the
network. Instead the server generates a nonce, a one-time random
number, and sends it to the client’s browser, which then hashes the nonce with
the user’s password and sends the resulting hash back to the server. The
server then performs the same hash and compares the result. This is
considerably more secure than Basic Authentication, though
not so widely used. One disadvantage of Digest Authentication is that it
requires setting up a different password file for each realm on the server, as
the realm name is used when creating the necessary hashes.
With Basic Authentication, one password file can be used across the
board.

To create an area protected by Digest Authentication, we use something like
the following.

<Directory "/var/www/htdocs/protected" >
 Options None
 AllowOverride None
 AuthType Digest
 AuthName "Protected Area"
 AuthDigestFile /usr/local/Apache/conf/digest_passwd
 AuthDigestGroupFile /usr/local/apache/conf/groups
 Require valid-user
 Order deny,allow
 Deny from all
</Directory>

This time we set AuthType Digest, and the AuthName "Protected Area"
directive is required. In place of AuthUserFile and
AuthGroupFile directives we use the AuthDigestFile and
AuthDigestGroupFile directives. The group file is the same as
previously, but we need to set up the password file using the command
htdigest -c /usr/local/apache/conf/digest_passwd "Protected Area"
user1
. Note the use of the htdigest program in place of
htpassword and the AuthName in the command. Again
the c option creates the file if it doesn’t exist.

Logs

Having detailed logs is important if we are going to track activity on our
server, whether to trace problems or potential violations. We can allow
detailed logs by including the following in our httpd.conf file:

LogLevel warn
LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" combined
LogFormat "%h %l %u %t "%r" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
ErrorLog /usr/local/apache/logs/error_log
CustomLog /usr/local/apache/logs/access_log combined

If you have several virtual hosts on your server, it is prudent to set a
separate log file for each host:

NameVirtualHost *
<VirtualHost *>
DocumentRoot "/www/htdocs/myserver"
ServerName "www.myserver.com"
ErrorLog logs/mysite/error_log
CustomLog logs/mysite/access_log combined
</VirtualHost>

Immunizing the configuration file

Once we have configured the server we should do one last thing. By setting
the immutable bit on the configuration file we make it much more difficult for
anyone to change the configuration. Do this by running chattr +i
/usr/local/Apache/conf/httpd.conf
.

Apache is generally a very secure piece of software but the default configuration
on many distros is often too lenient. By limiting the number
of modules and using a restrictive configuration we can considerably reduce the
risk of a break-in. When setting up your server, divide content into different
realms and be as restrictive as possible in what options you allow for each
area.

Mike Peters is a freelance consultant and programmer and long-time Linux user.