Apache HTTP Server is an open source web server developed by a community of developers and users, supported by non-profit corporation Apache Software Foundation. Apache web server is often placed at the edge of the server to serve httpd traffic hence it’s the most vulnerable service to an attack. Even though Apache has a good history about security, it does not mean Apache will deflect all security threats like XSS, Cross-Site Scripting, Cross Site Request Forgeries, Denial of Service, SQL Injection, PHP Injection, Session Hijacking, Info Leakage.
In this article I will show you how to secure Apache web server, but it’s not a good idea only rely on secure your Apache web server, you should do routine security audit for your whole system and your network to check for any known vulnerabilities. You can use Nessus, Qualys, BackTrack, to keep your servers checked.
Update your system regularly
First, make sure you’ve installed latest releases and security patches of Apache and add-on code like CGI, Perl, PHP scripts. New Apache security vulnerabilities are discovered quite often, monthly, weekly or even more often update Apache and related add-on scripts is a must for any web server. If you compiled and installed your web server, modules, or dependencies from source, make sure to test the new update on development environment before roll out to production server in case new updates break your system. Don’t forget to Update your whole system regularly does not matter you have Linux or Windows.
To update on Ubuntu/Debian based distro
# apt-get update; apt-get dist-upgrade
To update on Fedora/Centos/RedHat based distro
# yum update
Secure your SSH server
Most of us don’t host our websites at home/office, we colo our dedicated servers at data centers, some of use can’t afford dedicated servers so some user VPS (Virtual private server), or shared hosting. For those who mange their dedicated servers and VPS, well you have to remote control them via RDP (Remote Desktop Protocol) if you have Windows Servers, or SSH (Secure Shell). For Linux/Apache servers, you should harden and secure ssh server. If it’s possible, use SSH login without password and disable ssh password authentication to make it harder for attacker to attack your server in general.
Disable unused services
To secure your web server in general, I highly recommend you to check your server for all running services and open ports, disable all services that you don’t need on your server. Close all ports which should not face to the internet via iptables or at router/network level. You can use nmap for scanning the network to check on all ports that are open.
To show all services (both stopped and running)
# service --status-all
To show iptables rules
# iptables -L
To show runlevel information (redhat/centos/fedora)
# chkconfig --list
Check /etc/init.d Directory for suspicious scripts
# ls /etc/init.d
Check crontab for root users and Privileged User (must run as root)
# for user in $(cut -f1 -d: /etc/passwd); do crontab -u $user -l; done
Check cron scripts
# ls /etc/cron.d # ls /etc/cron.daily # ls /etc/cron.hourly # ls /etc/cron.monthly # ls /etc/cron.weekly
Disable unnecessary apache modules
By default, Apache enable many modules what your websites don’t need. It’s a good practice to disable unnecessary Apache modules to prevent unknown vulnerabilities.
To list enabled Apache modules
For Ubuntu/Debian based distros
# cat /etc/apache2/mods-enabled/* | grep -i loadmodule
To enable a module:
# a2enmod module_name
To disable a module:
# a2dismod module_name
For Centos/Fedora/RedHat based distros
# cat /etc/httpd/conf/httpd.conf | grep -i LoadModule
To enable/disable module, edit httpd.conf file and search for “LoadModule”, the one without hash sign (#) are enabled, the one with hash sign (#) in front are disabled.
# nano /etc/httpd/conf/httpd.conf
Run Apache under its own user and group
Most default Apache installation should have user and group as apache, there is nothing wrong with that. Make sure you don’t run apache with the same user/group with another services that you have in your server. Say you run mail server as the user nobody, and you run Apache with the same user. If your mail server is compromised, your Apache will be also compromised. Also never run any services as root, big NO. Any service run as root and be compromised, your whole system will be in a big risk. To check/change user/group, edit the httpd.conf file
For Fedora/Centos/Redhat based distro
# nano /etc/httpd/conf/httpd.conf
For Ubuntu/Debian based distro
# nano /etc/apache2/httpd.conf
Look for User and Group line, you are safe to use default setting which is “apache”, or you can create new user and set that new user here.
User apache Group apache
Prevent Information Leakage
Default Apache installation gives out quite some information about Apache itself like version, Operating System, Port, and hostname. People with bad intent to your server can look-up your web server info and then search for that specific OS or Apache version for vulnerabilities. To prevent that to be happened, you should hide what your Apache runs as much as possible to defense your web server. This is an example what an Apache 404 error page gives out
Not Found The requested URL /test/ was not found on this server. Apache/2.4.7 (Ubuntu) Server at namhuy.net Port 80
To Prevent Information Leakage, you have to modify your Apache configure files
For Fedora/Centos/Redhat based distro
# nano /etc/httpd/conf/httpd.conf
For Ubuntu/Debian based distro
# nano /etc/apache2/conf-enabled/security.conf
Search for ServerTokens and ServerSignature set them to
ServerTokens Prod ServerSignature Off
Restart your Apache2 or httpd server after the change
For Fedora/Centos/Redhat based distro
# service apache2 restart
For Ubuntu/Debian based distro
# service httpd restart
Sample 404 error output on my server after I set ServerTokens to Prod and ServerSignature to Off, virtually no info at all.
Not Found The requested URL /test was not found on this server.
Hide PHP Version
If you have installed PHP module (PHP: Hypertext Preprocessor) with Apache, you will want to hide PHP version in HTTP response headers to prevent another potential security threat. Apache web server shows PHP version by default via “X-Powered-By” in HTTP response headers to remote requests. As previous security tip i wrote above to hide Apache version to make Apache display as minimal information about the installed software version, it’s also a good security practice
to your web server.
To hide or disable PHP version, we need to turn expose_php variable off in php.ini file. By default expose_php is always set to On. Depends on your Linux distribution, php.ini file can be found in different directory.
For Fedora/Centos/Redhat based Linux distro
# nano /etc/php.ini
For Ubuntu/Debian based Linux distro
# nano /etc/php5/apache2/php.ini
Search for
expose_php = On
And change expose_php to Off
expose_php = Off
Disable Directory Listing
Apache Directory Listing or Directory Indexes requires apache module mod_autoindex to show a list of files and directories if the base index file index.php index.html are not available that you have under root/sub-directory. You should not enable this feature for your website root directory (or server wide), and only should enable Directory Listing for particular directory where you need it.
Lets say your website’s VirtualHost with DocumentRoot at /var/www/html directory, you should disable directory listing with -Indexes using Opions directive.
To disable directory listing side wide, place this inside your <VirtualHost *:80> and </VirtualHost> tag
<Directory /var/www/html/> Options -Indexes </Directory>
To enable directory for particular directory or sub directory on your website, I will call that directory listing for our sample
<Directory /var/www/html/listing> Options +Indexes </Directory>
Excluding Files: You can also hide certain files or file types using wildcard (*). Says you have a list with mix .mp3 and .wma files, but you only want to display/show .mp3 files and hide all .wma from the public. Place this inside <Directory> and </Directory> tags
IndexIgnore *.wma
Sample
<Directory /var/www/html/listing> Options +Indexes IndexIgnore *.wma </Directory>
To disable autoindex module completely from your http web server
For Fedora/Centos/Redhat based distro
# nano /etc/httpd/conf/httpd.conf
Search for autoindex_module line and comment it out by placing hash sign in front of the line.
LoadModule autoindex_module modules/mod_autoindex.so
to
# LoadModule autoindex_module modules/mod_autoindex.so
For Ubuntu/Debian based distro, you can either remove the module or rename it
to rename autoindex module
# cd /etc/apache2/mods-enabled/<h1>mv autoindex.conf autoindex.conf.bk</h1><h1>mv autoindex.load autoindex.load.bk</h1>
to delete autoindex module
# rm -rf /etc/apache2/mods-enabled/autoindex.conf<h1>rm -rf /etc/apache2/mods-enabled/autoindex.load</h1>
Deny browsing outside the document root
To prevent scripts or someone to access your server/filesystem outside the web server document root, you have to add this block to your virtualhost configuration.
<Directory /> Order Deny,Allow Deny from all </Directory>
If you want to allow access to a particular directory, say “download”, add this block after the block above. What we are trying to do is to deny everything, and then allow only directories that we want to.
<Directory /var/www/html/download/> Order Deny,Allow Deny from all </Directory>
This is also done with the Options directive inside a Directory tag. Set Options to either None or -Includes
Options -Includes
Disable Server Side Includes
Apache SSI (Server Side Includes) is a useful Apache feature which let you add the contents of an external file across multiple pages on your website, SSI can also access and display your server’s information such as time, date, visitor’s IP address…
Here are some small samples how to use SSI (simply add these code to any html file)
To display document filename
<!--#echo var="DOCUMENT_NAME" -->
To display current server date, and time
<!--#echo var="DATE_LOCAL" -->
To include the contetns of an external file
<!--#include file="external.htm"-->
or
<!--#include virtual="/external.htm"-->
Sounds good isn’t it, but SSI has some potential security risks itself. SSI is enabled by default, all SSI enabled file will make Apache use more server’s resources by analyzing all of the directives included within the files. You don’t have much problem if you run your Apache web server on a VPS or dedicated server, but if you share your web server resources with other people (shared hosting environment), the impact will be significant.
Secondly, another SSI security is that SSI allow anyone to execute any CGI scripts. If an attacker execute a server side include statement, he can execute arbitrary operating system commands or include a restricted file contents to display those contents on a webpage. If you must use SSI, only enable SSI directives for certain page or directories.
For example with this SSI tag, attacker can list all directories under root directory on a Linux system.
<!--#exec cmd="/bin/ls /" -->
To turn off the exec form of includes in a directory, place this code within <directory> tags
Options IncludesNoExec
To turn off server side includes, place this code within <directory> tags
Options -Includes
Only allow required HTTP methods
There are several different types of HTTP methods (for example OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT…) for different purposes, you should only allow which methods you need for your websites to work properly and disable the rest using ModSecurity in Apache. If you don’t have ModSecurity installed on your server, you can use LimitExcept which is a directive in Apache config file. Most modern websites use WordPress, PHPbb and such would need GET, HEAD AND POST, so we are going to deny the rest. Place LimitExcept inside <location> block
<Location /> Order allow,deny Allow from all <LimitExcept GET POST HEAD> Deny from all </LimitExcept> </Location>
TRACE is a HTTP request method to debug, TRACE will echo back input to the user which will allow attacker to get your website or user’s credentials. You can’t block TRACE method with LimitExcept, You will have to turn TraceEnable Off in Apache configuration file, please this line in Apache configuration file after ServerTokens and ServerSignature lines
TraceEnable Off
If you don’t have access to Apache configuration file, you can use .htaccess file with mod_rewrite module to disable TRACE, place these lines into your .htaccess file. (replace www.namhuy.net to your domain name).
RewriteEngine On RewriteCond %{REQUEST_METHOD} ^TRACE RewriteRule .* - [F]" - www.namhuy.net
Use custom Error Pages
Every web server has their own default error pages, as we talked above we are trying not to show information from our web server as much as possible. Attackers can easily make your web servers to display error pages purposely to gather information. Default error pages can give out Operating System, Linux Distro, web server, and sometimes web server version. It’s always a good security practice to use custom error page rather than default error pages to make it harder for the attackers to identify what you are running on your server. These are some generic error codes that you should create custom error pages
- 400 – Bad Request : The server did not understand the request due to bad syntax.
- 401 – Unauthorized : The visitor must by authorized (e.g., have a password) to access the page.
- 403 – Forbidden : The server understood the request but was unable to execute it. This could be due to an incorrect username and/or password or the server requires different input.
- 404 – Not Found : The server cannot find a matching URL.
- 500 – Internal Server Error : The server encountered an unexpected condition which prevented it from fulfilling the request.
To use Custom Error Pages, fist you have to create each web page for each error code, error pages can be in html, php, asp, or whatever you want. Next you can either insert ErrorDocument into Apache configuration file or .htaccess file.
ErrorDocument 400 /400.htmlErrorDocument 401 /401.htmlErrorDocument 403 /403.htmlErrorDocument 404 /404.htmlErrorDocument 405 /405.htmlErrorDocument 500 /500.html
The syntax of the ErrorDocument directive is:
ErrorDocument <3-digit-code> <action>
<action> can be internal with a “/” or external with full URL, or text to be displayed (text must be wrapped inside quotes (“).
Disable .htaccess
If you have fully access to your web server (dedicated or vps), you should always disable .htaccess for better security. The .htaccess file is very useful: it’s flexible, it works everywhere and the modifications are processed instantaneously. Almost all web hosting provider support .htaccess since Apache web server is being shared with other users. For example web server with cpanel installed, there are many users share the same physical server, so it’s impossible to satisfy all users with the same Apache configuration.
.htaccess file sounds great isn’t it, so why disable .htaccess !? Let’s talk about server security first. By allow .htaccess to take over control of the server configuration, attacker can add malicious configuration to access the host machine, cluster or cloud where the vhost is hosted. For example
AddType application/x-httpd-php .pdf .asp .py .pl
with that code in .htaccess file, attacker can hide PHP as .pdf file, or any another language
Now let’s talk about server performance with .htaccess enabled. .htaccess files are resource hogs. Every request to your website, apache will have to read server’s disk many times to looks for these .htaccess files in every directory. Say there are some bad php plug-ins which have many sub-directory can easily decrease your server performance quickly over hundreds of vhosts.
To disable .htaccess file, place this in your virtual host configuration file
<Directory />AllowOverride none</Directory>
Disable ETag
FileTag or ETag is a apache’s directive to create ETag response header. Entity tags (ETags) are a mechanism to check for a newer version of a cached file which allows remote attackers to get sensitive information from your Apache server. There was a big in Apache (CVE-2003-1418) about FileEtag that may reveal inode values or MIME boundary (Apache child process ID or PID). That bug is apparently has been fixed but you should disable it to prevent this vulnerability. You can add this code to .htaccess file or httpd.conf which is better.
Header unset ETagFileETag None
Enable X-XSS-Protection
XSS (Cross-Site Scripting) is one of the most common application layer hacking techniques. XSS injects malicious scripts to the remote server. There are two type of XSS, Non-Persistent and Persistent. Non-Persistent XSS requires users to visit a specific infected link, after that the malicious scripts from the infected link will be executed by the user’s browser. In another hand, with Persistent XSS, attacker will store malicious scripts in a remote storage (mostly database). When users visit infected webpage, the malicious scripts will send all of the victim’s information to the attacker server without the victim’s knowledge.
To enable X-XSS-Protection, you will need mod_headers enabled, and add this codes to your apache configuration file.
<IfModule mod_headers.c> # enable X-XSS-Protection for Internet Explorer 8 and newer Header set X-XSS-Protection: "1; mode=block" # hide server header (apache and php version) Header unset Server # Only allow JavaScript from the same domain to be run. # don't allow inline JavaScript to run. Header set X-Content-Security-Policy "allow 'self';" # Don't allow any pages to be framed by my site or any others Header set X-Frame-Options DENY # Add Secure and HTTP only attributes to cookies Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure # prevent Clickjacking Attack Header always append X-Frame-Options SAMEORIGIN </IfModule>
Check Apache log files regularly
You should check Apache’s error log often so you can quickly resolve errors/configured configurations. Most of errors stored in Apache Error Log are warning or bunch of file does not exist error. Sometimes you will see some fatal warnings/errors indicate problem has occurred to your web server, you should always fix those events to prevent further serious problem which may cause your web server fail to run.
For Ubuntu/Debian based distros
# cat /var/log/apache2/error.log
For Centos/Fedora/RedHat based distros
# cat /var/log/httpd/error_log
Keep HTTP configuration file simple
Last but not least, try to keep Apache configuration file as simple as possible. Default Apache configuration is very long with a lot of comments (not a bad thing if you are new), but if you know what you are doing, you can remove those comments to make HTTP configuration file easier to read.