Introduction


This Howto describes the most typical webserver hardening steps to improve security. In focus are Linux servers running the Apache web server. Example settings have been evaluated on OpenSuse 12.1.

1. Configure the Linux Firewall


On the operating system level, we configure the Linux iptables firewall to allow only the ports for the services we intent to be accessed over the network. For a web server, these are typically:

The list above is only an example, please select only the ports that are really being used. In some cases the server management access is placed on a dedicated management network interface, in which case the firewall should open SSH only for that specific interface.

susie114:~ # iptables -L input_ext
Chain input_ext (1 references)
target     prot opt source               destination         
           all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere             PKTTYPE = broadcast
ACCEPT     icmp --  anywhere             anywhere             icmp source-quench
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
ACCEPT     udp  --  anywhere             anywhere             udp dpt:snmp
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:https
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh
DROP       all  --  anywhere             anywhere             PKTTYPE = multicast
DROP       all  --  anywhere             anywhere             PKTTYPE = broadcast
DROP       all  --  anywhere             anywhere

2. Configure Apache to explicitly run on listed IP and Ports


Run and listen only on the HTTP/S port 443, per Apache configuration. The actual website should be configured to run on dedicated IP's, in my case I also run a mini-site on localhost for monitoring. In reaal live, this would be a internal-only network interface IP. Explicitly configuring the IP prevents running Apache unintentionally on additional IP such as the Backup network IP.

susie114:~ # vi /etc/apache2/listen.conf
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports. See also the  directive.
#
# http://httpd.apache.org/docs-2.2/mod/mpm_common.html#listen
...

Listen 70.85.16.97:80
Listen 127.0.0.1:80

# Use name-based virtual hosting
NameVirtualHost 70.85.16.97:80
...

3. Verify Apache runs as a non-privileged user


Apache can be configured to run under a non-privileged user account. This is a standard configuration setting, but it is so vital to our security that I would like to confirm it anyways. On OpenSuse and many other Linux distributions, the user account for Apache is called wwwrun, and the group is set to www.

susie114:~ # vi http.conf
...
# run under this user/group id
Include /etc/apache2/uid.conf

susie114:~ # cat uid.conf
User wwwrun
Group www

We quickly check that Apache is indeed running under this user ID, as expected:

susie114:~ # ps -U wwwrun
  PID TTY          TIME CMD
13793 ?        00:00:00 httpd2-prefork
13996 ?        00:00:00 httpd2-prefork
14157 ?        00:00:00 httpd2-prefork
...

Finally, we check the user shell to ensure that for this user ID, no interactive login is possible.

susie114:~ # grep wwwrun /etc/passwd
wwwrun:x:30:8:WWW daemon apache:/var/lib/wwwrun:/bin/false

4. Enable HTTPS for encryption


Standard HTTP is a cleartext protocol suited only for public information. For applications, it is often advisable to configure HTTPS and encrypt the transmitted application data. In order to enable HTTPS, Apache needs the mod_ssl module enabled, and a certificate needs to be created. There is numerous help for doing it, let's just verify our settings here:

susie114:~ # vi /etc/sysconfig/apache2
...
# 
APACHE_MODULES="ssl ... mime negotiation setenvif status deflate rewrite php5 authz_default"
...
#
APACHE_SERVER_FLAGS="SSL STATUS"
...

After we checked that the SSL module is enabled, we will check if the module is actually loaded by Apache:

 susie114:~ # httpd2 -t -D DUMP_MODULES
Loaded Modules:
 core_module (static)
 mpm_prefork_module (static)
 http_module (static)
 so_module (static)
 ssl_module (shared)
...
Syntax OK

For best SSL security, we can disable weak (low and medium) encryption algorithms and use only the methods marked "strong": 3DES, AES with SSLv3 or TLSv1. This is typically set within the virtual host configuration:

susie114:~ # vi /etc/apache2/vhosts.d/ssl.conf
        #   SSL Cipher Suite:
        #   List the ciphers that the client is permitted to negotiate.
        SSLCipherSuite HIGH

5. Linux Application Firewall - AppArmor


A very strong measure for protection is to place Apache under the control of an application firewall. OpenSuse comes with AppArmor, which prevents access to any resource outside of a pre-defined profile. This protects against some web application bugs. For example, poorly written code could trick the webserver to reveal sensitive information such as /etc/passwd.

# httpd2 -t -D DUMP_MODULES | grep apparmor
Syntax OK
 apparmor_module (shared)

Below is a example of a Apache configuration profile for a specific virtual host. AppArmor has a convenient learning mode that helps identify the necessary access rights.

6. Disable unnecessary modules, methods and locations


Next, we disable all unnecessary Apache modules, methods and web locations. In a specific example for OpenSuse, modules such as mod_dir, mod_imap, mod_userdir, mod_asis are deemed not necessary. They are removed from /etc/sysconfig/apache2 and a check of modules verifies the result.

susie114:~ # vi /etc/sysconfig/apache2
...
#
APACHE_MODULES="ssl ... mime negotiation setenvif status deflate rewrite php5 authz_default"
...

susie114:~ # httpd2 -t -D DUMP_MODULES
Loaded Modules:
 core_module (static)
 mpm_prefork_module (static)
 http_module (static)
 so_module (static)
 ssl_module (shared)
...
Syntax OK

Now we remove default web locations such as /manual, /icons and /cgi-bin. Technically, they are not particularly dangerous, with the exception of /cgi-bin. The manuals come with the apache-doc package, simply de-installing that package is enough. Icons provide a way for Apache to show directory content in a nice, fancy way. However with mod_autoindex disabled, they will do little harm. Default CGI settings can be more dangerous. CGI settings are typically configured as aliases in virtual hosts and can be disabled there. Alternatively, to be sure, the default CGI files listed below could be removed completely. If no CGI is used at all, removing mod_cgi will be an additional measure.

susie114:~ # vi /etc/apache2/default-server.conf
...
# We include the /icons/ alias for FancyIndexed directory listings.  If you
# do not use FancyIndexing, you may comment this out.
#
#Alias /icons/ "/usr/share/apache2/icons/"
...
# The manual... if it is installed ('?' means it won't complain)
# Include /etc/apache2/conf.d/apache2-manual?conf

susie114:~ # ls -l /srv/www/cgi-bin
total 40
-rwxr-xr-x 1 root root 26284 Oct 20  2009 info2html
-rw-r--r-- 1 root root  3233 Oct 20  2009 info2html.conf
-rwxr-xr-x 1 root root  5381 Oct 20  2009 infocat
lrwxrwxrwx 1 root root    16 May  2 15:45 php -> /usr/bin/php-cgi

Finally, we disable the unneeded methods HTTP TRACE and TRACK, and, optionally, the implementation for FileETags. Etags are best disabled by setting FileETag None on a global level, and only enable them explicitly with FileETag All (INode MTime Size) for directories such as those under WebDAV.

susie114:~ # vi /etc/apache2/vhosts.d/frank4dd.com.conf

...
    # webserver hardening: disable the TRACE|TRACK methods
    RewriteEngine on
    RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
    RewriteRule .* - [F]

    # webserver hardening: disable the default FileETag response
    FileETag None
...

7. Hide Server and OS Details


Although not the strongest measure, hiding the Apache version string is recommended to prevent conclusions about the exact revision used. In this example, we will reduce the server response to the minimum possible:

susie114:~ # vi /etc/sysconfig/apache2
...
# see http://httpd.apache.org/docs-2.2/mod/core.html#servertokens
#
APACHE_SERVERTOKENS="ProductOnly"
...

# telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / \HTTP 1.0

HTTP/1.1 200 OK
Date: Thu, 03 May 2012 09:27:25 GMT
Server: Apache
Last-Modified: Mon, 12 Dec 2011 13:51:59 GMT
Accept-Ranges: bytes
Content-Length: 10859
Connection: close
Content-Type: text/html
...

8. Enable Apache Access Control Lists


Restricting access is by far one of the best protection methods, because what cannot be accessed cannot be harmed. Apache has a module called mod_authz_host that provides flexibe configuration. By using this module, each website URL area can get an dedicated access list, defined on the "least access" principle using IP ranges (DENY FROM ALL, followed by a ALLOW FROM XXX). Even if the website is public, in makes sometimes sense to restrict access on a country level by using a IP-address assignment map. Below is a simple ACL example, protecting access to the server-status web resource.

susie114:~ # vi /etc/apache2/mod_status.conf
#
# Allow server status reports generated by mod_status,
# with the URL of http://servername/server-status
#
# see http://httpd.apache.org/docs-2.2/mod/mod_status.html
#
<IfModule mod_status.c>
    <Location /server-status>
        SetHandler server-status
        Order deny,allow
        Deny from all
        Allow from localhost 127.0.0.1
    </Location>
</IfModule>

9. Enable user authentication


- Writeable areas are further protected by individual user authentication, where possible we use client certificate authentication for highest access security.

10. Set up Apache logging and monitoring


Setting up logging and monitoring helps to detect any abnormal and abusive traffic to our website.

Setting up the log location is typically done on the virtual host level, separating the logs per website:

susie114:~ # vi /etc/apache2/vhosts.d/frank4dd.com.conf
...
    ErrorLog /var/log/apache2/www.frank4dd.com-error.log
    CustomLog /var/log/apache2/www.frank4dd.com-access.log combined
...

Setting up the log rotation is best done using logrotate in Linux:

susie114:~ # vi /etc/logrotate.d/apache2
/var/log/apache2/*.frank4dd.com-*log {
    compress
    dateext
    maxage 60
    rotate 45
    daily
    notifempty
    missingok
    create 644 root root
    postrotate
     /etc/init.d/apache2 reload
     /srv/app/webalizer/bin/frank4dd.com-cronscript.sh
    endscript
}
...

For basic availability and load monitoring, a tool such as Nagios is typically used. With some magic, it can also alert for additional security-relevant criteria, such as authentication failures, or authentication is in place. See the Nagios example for a minimal setup.

For monitoring web access statistics, we use an analytics tool such as Piwik or Webalizer. For a minimal setup, see this local Webalizer example.

For monitoring error conditions and exceptions, an automated log monitoring tool such as Logwatch can be used to aggregate and highlight problems.

In bigger sites, logs, including those from Apache, should be send and stored on a dedicated, central log analysis system. Several tools and vendors compete in this space.

Additional Measures


First, let's verify our hardening by running a vulnerability scan against our system. In my example, I am using the free OpenVAS scanner with the Inovasc scan client. An example scan result shows what we might have missed.

Other great tools to further improve the systems security are:

If there is one final message: No tool can replace the skills of a watchful administrator. Even if installed by a professional, running and interpreting output from these tools requires knowledge of the server, the application and the symptoms of an attack. Security outsourcing fails because it breaks up this combination. It is practised because real hacks are rare, and the resulting risk is taken to save costs.

Links and Credits


See also: