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:
- TCP port 22 (SSH)
- TCP port 80 (HTTP)
- TCP port 443 (HTTPS)
- UDP port 161 (SNMP)
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 thedirective. # # 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:
- Web Application Firewall - ModSecurity
- Ruleset for the Firewall above - OWASP ModSecurity Core Rule Set Project
- DoS and BruteForce Mitigation - mod_evasive
- File Integrity Checker - Tripwire
- Intrusion Detection - Snort
- Brute Force Blocker - fail2ban
- Multi Purpose - CSF & LFD
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
- The Apache Software Foundation, home of the Apache Webserver