This page collects hints how to improve the security of Apache web servers running Debian. This is a work in progress and very incomplete.

Disable what you don't need

Disable Suexec

If you don't use mod_suexec, you should disable the suexec helper binary. In current versions (2.2.8-5 and later), this is done by uninstalling the apache2-suexec/apache2-suexec-custom packages.

Up to Debian Etch, this could only be done by removing the suid bit with

# do not use for current versions
dpkg-statoverride --add --update root www-data 644 /usr/lib/apache2/suexec

This will survive updates of Apache. Be sure to write it down somewhere, or you may be confused if you need mod_suexec later and it doesn't work.

Disable modules

Disable Apache modules that you don't need. Good candidates are:

Restrict outgoing connections

A web server mostly accepts connections but usually only needs to initiate very few connections itself. Therefore it makes sense to limit the possible outgoing connections to what is actually needed. This makes it much more difficult for an attacker to do harm once he has exploited some web application.

iptables example

You can do this with iptables. As an example, we will take an Apache installation with mod_php and squirrelmail, that needs to connect to smtp/imap on localhost for outgoing/incoming mails. The relevant rules may look like the following. Of course, you have to adapt them to your other iptables rules and to the web applications you run:

modprobe ip_tables
modprobe ip_conntrack
modprobe ipt_owner

iptables --new-chain out_apache

# for performance, the first rule in OUTPUT should usually accept
# packages belonging to established connections
iptables --append OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# put everything sent by the Apache run user www-data into the chain out_apache
# that we created above
iptables --append OUTPUT -m owner --uid-owner www-data -j out_apache

# for new connections to ports 143 (imap) and 25 (smtp) on localhost, return to the OUTPUT queue
# (use RETURN instead of ACCEPT so that further restrictions in the OUTPUT queue still apply)
iptables --append out_apache -p tcp --syn -d 127.0.0.1 --dport 143 -j RETURN
iptables --append out_apache -p tcp --syn -d 127.0.0.1 --dport 25  -j RETURN

# reject everything else
iptables --append out_apache -j REJECT

Restrict resource usage

Number of processes

Limit the number of Apache processes to a number that is suitable for your server. If you allow too many processes, your server may start swapping or even killing processes if it runs out of memory.

If you use the prefork MPM, you can estimate the memory one process needs in the following way. Use top to observe the apache processes during normal operation (this means not immediately after startup). Subtract the value in the SHR column from the value in the RES column. Then divide the memory available for apache (leaving a bit of reserve) by this value. Use the result as value for MaxClients. Example: With RES=7000k, SHR=2500k and 400M available for Apache, the result is 400/(7-2.5) = 89.

Mitigate memory leaks

It happens frequently that apache, some module, or some mod_php extension has a memory leak. This can be mitigated by setting

MaxRequestsPerChild 10000

If you have severe problems with memory leaks, a value as low as 500 can make sense.

Incoming Connections

To restrict the number of connections used by a single IP address, use iptables' connlimit module. For example:

iptables -I INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 25 -j REJECT --reject-with tcp-reset

The value for the connection limit (25 in the above example) depends very much on the size of your site and the value you have configured for MaxClients. In general the connection limit should not be above one third of the configured MaxClients. For large sites, the correct value may be much lower. Do keep in mind, however, that large proxy servers may legitimately create a large number of connections to your server.

File permissions

Web content

For historical reasons, the Apache runs as a user named www-data. This is somewhat misleading since normally, the files in the ?DocumentRoot (/var/www) should not be owned or writable by that user. To find files with wrong permissions, use:

find /var/www -user www-data
find /var/www ! -type l \( -perm /o=w -o -perm /g=w -group www-data \)

Copies of scripts

If you manage you web content with a version control system, make sure the supplementary (hidden) files are not readable via Apache. Otherwise an attacker may be able to read the source code of the scripts you use. You should make sure that access to such directories is either denied by the Apache configuration or the file permissions are such that the www-data user cannot read them.

The same problem exists with backup files. A file named auth.php.bak may not be interpreted as script but be sent to the client as source code.

To find hidden and backup files in the document root, use something like this:

find /var/www -name '.?*' -not -name .ht* -or -name '*~' -or -name '*.bak*' -or -name '*.old*'

SSL key files

Make sure your SSL keys are only readable by the root user.

Other Apache configuration and common pitfalls

conf.d/security

Since Lenny, the file /etc/apache2/conf.d/security contains some security related settings. Look at the comments and adjust it to your needs.

Beware of certain RewriteRules

RewriteRule guesses if the target is a file name on disk or an URL: If a file with the name exists on disk, mod_rewrite will serve that file. Only if the file (or rather the top-most directory part) does not exist will it treat the target as an URL. This unexpected behavior can lead to security issues. If you have a RewriteRule that uses input from the client as target, like

# INSECURE configuration, don't use!
RewriteRule ^/old/directory/(.*)$  /$1

A request for /old/directory/etc/passwd will be rewritten to /etc/passwd and will serve that file to the client. To avoid this behavior, use the PT flag:

RewriteRule ^/old/directory/(.*)$  /$1  [PT]

Don't use Limit/LimitExcept

The configuration blocks <Limit> and <LimitExcept> have very confusing semantics. If used wrongly, they can disable other, apparently unrelated authentication or authorization directives in your configuration. It's better to avoid them altogether. To disable the HTTP TRACE method, set TraceEnable off in conf.d/security. To disallow other methods, use mod_rewrite. If you really have to use Limit/LimitExcept, check that all your authentication/authorization is working as intended.