Author: Mike Peters
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
in order to only allow access to certain users.
user2
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"
. Note the use of the
user1htdigest
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.