This
document is a guide to installing and hardening an Apache 2.0 web server to
common security standards. It will guide
you through practical measures to harden your Apache server, by way of example.
Because
a web server is often placed at the edge of the network, it is one of the most
vulnerable services to attack.
Therefore, it’s vital that you follow this guide to ensure that:
1)
The opportunity to compromise the web server is limited
2)
Should the web server be compromised, the damage potential to the rest
of the network, data, and systems is limited.
Follow the hardening guidelines in the The Center for
Internet Security. Hardening the
host O/S ensures that, should someone compromise the security of your web
server, the amount of damage that they could inflict will be minimized.
1.2 Create the directories to hold the Apache files
It’s important to separate the binaries /bin, docs (/htdocs), and logs (/logs) into separate partitions
on the system. You can choose whatever
root you want, but this example will use /opt/apache2 as the root directory for
the Apache web server.
1.3 Create the host groups for administering and
running the server.
Create a distinct group for all the users who will
have permission to change the configuration, start, and stop the web
server. For example, if you want to call
the group “webadmin”, create it like this:
# groupadd webadmin
Create a distinct group
for the web server user – no one will actually log into this group, but it will
only be used to hold the userid which will run the
web server. For example, if you want to
call that group “webserv”, create it like this:
Take note that you should not create a “web
developer” group on this host. Since this
is a hardened production host you must not provide web developers login
accounts on this system. Instead,
developers should deploy documents and code to the server using your
code/content deployment system, such as Kintana’s
Apps*Integrity.
Never run the web server
as root; if the web server is ever
compromised, the attacker will have complete control over the system. Instead, the best way to reduce your exposure
to attack when running a web server is to create a unique unprivileged userid for the server application. The userid nobody is often used for this purpose,
but a userid and group that are unique to the web
server is a more secure solution.
By default the web server uses privileged ports (port 80 and 443) and, when configured for
secure operation, must have root privileges to open its log files and start the
dæmon.
(Therefore, the web server daemon will have to be started as “root”,
unless you configure it to use a port higher than 1024.) Once the server's startup tasks are complete,
all active instances can run as the unprivileged user.
Use the following command line entries as patterns
for creating a group and user for the web server. Here’s an example if you were to use “webserv” as the user:
# useradd -d /opt/apache2/htdocs -g
webserv -c "Web Server" webserv
It’s important that no one can successfully execute
a password guessing attack against this account, so in this step, we’ll restrict
this account so that no one can log into it.
1.5.1 Issue this command to lock the password for
the web server account:
# passwd –l webserv
Password changed.
1.5.2 To
be sure the account is locked, issue the command:
# grep webserv /etc/shadow
…a :!:
at the beginning of the line indicates that the password is locked.
1.5.3 Issue this command
to remove the shell for this account:
# usermod –s /bin/false webserv
1.5.4 To be sure the
account is locked, issue the command:
# grep webserv
/etc/passwd
…/bin/false
at the end of the line indicates that the shell is set to a
non-existent shell.
1.5.5 Test the web
server account to be sure you can’t login.
Issue this command to try to log in:
> login
webserv
By
default, web servers return information about the product and version they are
running in the Server variable of the HTTP header. This information can be very useful to
hackers, enabling them to target attacks to that specific server. To prevent that information from being
returned from the web server, this step shows you how to modify that header and
build your own copy of the web server.
Because
web servers often host sensitive information, or allow users to log in with
plain-text passwords, it’s important to encrypt the HTTP traffic. Therefore, this section will show you how to
configure mod_ssl on your web server.
Note: Don’t build the web server on your
production, hardened host. Build it on a
staging or development server (with identical O/S), and then copy it to your
production host.
These steps will guide you through downloading Apache
source code, validating it, compiling it, and installing it. We don’t recommend use of pre-compiled or DSO
versions. DSO versions may allow a
hacker to introduce new “features” without having to recompile the code.
If you intend to add other module to your Apache web server
installation, repeat the validation steps below for each module you add.
Ensure that you retrieve the latest copy, so that
you have cumulative bug fixes and security patches. You can download it from the Apache site.
From here, download four files:
1) The Apache source code
itself, called something like httpd-2.0.45.tar.gz.
2) The PGP keys for the
Apache signers: a file named “
3) The PGP key for this
source distribution, called something like httpd-2.0.45.tar.gz.asc
4) The MD5 checksum for this
source distribution, called something like httpd-2.0.45.tar.gz.md5
wget
http://www.apache.org/dist/httpd/httpd-2.0.45.tar.gz
wget http://www.apache.org/dist/httpd/
wget
http://www.apache.org/dist/httpd/httpd-2.0.45.tar.gz.asc
wget http://www.apache.org/dist/httpd/httpd-2.0.45.tar.gz.md5
To ensure that you have an authentic version from
the Apache Group, and that it’s not been tampered with (remember, there are
many mirrors from which you can download the Apache source), you should check
the PGP signature. If you don’t have PGP
installed on this server, you can validate these files on another machine.
a)
If you don’t already have them in your PGP keyring,
import the public keys from the Apache Group into your keyring:
~> pgp –ka
b)
Check the PGP signature:
~> pgp
httpd_2.0.45.tar.gz
…if the signature is
correct, you should get something similar to this:
-- CUT --
File
'httpd-2.0.45.tar.gz.asc' has signature, but with no text.
Text is assumed to be in file
'httpd-2.0.45.tar.gz'.
Good signature from user "Justin R. Erenkrantz
<justin@erenkrantz.com>".
Signature made 20
WARNING: Because this public key is not certified with
a trusted signature, it is not known with high confidence that this public key
actually belongs to: "Justin R. Erenkrantz
<justin@erenkrantz.com>".
The
fact that it says, “Good Signature from…” is what we’re looking for here. The WARNING statement indicates that we’ve
not verified this signature with a 3rd party, which is ok here.
2.3 Verify the MD5 checksum for the Apache source.
MD5
is a way to validate the integrity of the file itself, much more reliable than
checksum and similar methods. Normally,
mismatches in the MD5 checksum from the Apache source are the result of
download errors or file corruption. If
you don’t have MD5 on your system, you can download it from here.
Compare
the results of these two commands – visually inspect them to ensure they match (if
they don’t, download it again):
~> pwd
/usr/local/build
~> cat httpd-2.0.45.tar.gz.md5
MD5 (httpd-2.0.45.tar.gz) =
1f33e9a2e2de06da190230fa72738d75
~> md5
apache_1.3.27.tar.gz
MD5
(httpd-2.0.45.tar.gz) = 1f33e9a2e2de06da190230fa72738d75
2.4 Extract the zipped Apache source file.
Finally, you need to
unzip and untar the source file.
~> /pwd
/usr/local/build
~> tar xvfz
httpd-2.0.45.tar.gz
This will create a new
directory under your current one, named “httpd-2.0.45”.
SSL support requires an SSL library on your system,
such as OpenSSL. If you’re not sure how to find and install
it, look at the Apache
1.3 hardening guide. This section will walk you through
configuring your SSL certificate for encrypting your HTTP traffic. It will help you build a validated
certificate and install it on your web server.
We’ll add the configured certificates to the Apache configuration in the
next step.
Using OpenSSL, the
following command will create a 1024-bit private key named, “private.key” and generate a certificate signing request
(CSR). You need to have the CSR signed
by a Certificate Authority (CA) who can validate your identity. When prompted
to input information, note the answers in bold print below. (Answer the prompts with the information
relevant for your server, of course).
Note: If you
provide a challenge password, you will be unable to start the web server
unattended. We don’t recommend providing
a challenge password, just leave it blank.
~> pwd
/usr/local/build
~> openssl
req -nodes -newkey rsa:1024
-keyout /usr/local/build/server.key
-out /usr/local/build/server.crt
Using configuration from /usr/share/ssl/openssl.cnf
Generating a 1024 bit RSA
private key
................++++++
.......++++++
writing new private key to
'server.key'
-----
You are about to be asked
to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a
DN.
There are quite a few fields
but you can leave some blank
For some fields there will
be a default value,
If you enter '.', the
field will be left blank.
-----
Country Name (2 letter
code) [AU]:US
State or Province Name
(full name) [Some-State]:NC
Locality Name (eg, city) []:
Organization Name (eg, company):XianCo
Systems, Inc.
Organizational Unit Name (eg, section) []:InfoSec
Common Name (eg, YOUR name) []:xianshield.xianco.com
Email Address []:webmaster@xianshield.xianco.com
Please enter the following
'extra' attributes
to be sent with your
certificate request
A challenge password []: <blank>
An optional company name
[]: <blank>
Most importantly, make
sure your “Common Name” above matches the DNS name of your server. The locale information is less important, but
we think it’s best to use the locality of the server itself.
Next, you
need to submit your CSR for signing by a CA.
This will eliminate the “warning dialog” that a browser will pop up when
a user accesses your site. This is
because the user’s browser has a set of trusted CAs
that will prevent you from being notified if the web server’s site certificate
is signed by a CA you’ve trusted in your browser already (such as Verisign or
Send
your request for a certificate to the CA.
Include your name, your web server (Apache, in this case) your OS, and
of course, the .csr (certificate signing request).

The names aren’t important, they just have to match
what’s in conf/ssl.conf. You will receive 2 files from the
mv “XianCo CA (01-03).cer” ca.crt
mv xianshield.cer
server.crt
Since you received these certs
via email, and they’re now sitting on your laptop, we need to copy both server.crt and ca.crt to the server. We’ll copy them up to /usr/local/build. We’ll move
them both to the appropriate locations under conf/ssl.conf later.
scp
*.crt xianshield:/usr/local/build/.
We want to remove/modify the default HTTP response
header parameter for the “Server:” token to hide the identity of our web
server. (You’d be surprised how many
vulnerability scanners are looking for specific versions of Apache.) To do this, we must open a header file (httpd.h) prior to compiling the
server. To do this, edit the ap_release.h file located in ${ApacheSrcDir}/include
~> pwd
/usr/local/build/httpd-2.0.45/include
~> vi ap_release.h
…
#define
AP_SERVER_BASEVENDOR "Apache Software Foundation" ß
Change this…
#define
AP_SERVER_BASEPRODUCT "Apache"
ß and
this
These are the lines you want to change; change these
to remove references to Apache. We’ll
hide the actual version using the ServerTokens directive in the httpd.conf file.
Example:
#define
SERVER_BASEVENDOR "Network Services"
#define
SERVER_BASEPRODUCT "Networks,
Inc."
There
are a few standard modules that should be disabled when you set up the Apache
web server.
Generally,
the following modules make it easier to configure/support your web server but
also give too much information to attackers.
We recommend that you disable the following default modules for your
production server:
info: gives out too much
information about your web server to potential attackers.
status: gives out server stats via
web pages
autoindex: provides directory
listings when no index.html file is present
imap: provides server-side
mapping of index files
include: provides server-side
includes (.shtml files)
userdir: translates URLs to
user-specific directories
auth: you won’t need it – you’ll
set up authentication against LDAP via mod_ldap
Here are two modules that will provide strong
authentication and encryption for your web server. If you have any protected content on your web
server, it’s important that you only allow your users to access it over SSL,
otherwise your user passwords will be sent in clear text, subject to snooping.
ssl: Encrypts the traffic from
the browser to the web server – an important means of protecting login
passwords and sensitive data.
auth_ldap: Allows you to validate
passwords against ldap.xianco.com or other LDAP.
It’s important that you
don’t set up your own userid/password store, since it
propagates passwords into insecure locations.
Instead, you should modify your configuration to defer authentication to
a central store, such as a centrally maintained LDAP. To authenticate against an LDAP store, you
need to compile Apache with support. In
order to use mod_ldap, you’ll need LDAP libraries
installed on your system. You can use OpenLDAP or Netscape
Directory SDK for the LDAP client libraries.
Here’s how to configure Apache with these options:
~> pwd
/usr/local/build/httpd-2.0.45
~> sudo
./configure –-prefix=/opt/apache2 \
--enable-so \
--enable-ssl \
--with-ldap
\
--enable-ldap \
--enable-auth-ldap \
--disable-info \
--disable-status \
--disable-autoindex \
--disable-imap \
--disable-include \
--disable-userdir \
--disable-auth
checking for chosen
layout... Apache
checking for working mkdir -p... yes
checking build system type...
sparc64-unknown-linux-gnu
checking host system
type... sparc64-unknown-linux-gnu
checking target system
type... sparc64-unknown-linux-gnu
Configuring Apache
Portable Runtime library ...
…
Now
that the software is validated and configured, it’s time to compile it. Since you won’t have a compiler on your
production host, we’ll compile and install it on a separate server, then
tar/compress it and scp it to your production
host. You’ll need to run make
using “sudo” so that Apache knows it
can use ports < 1000.
~>
pwd
/usr/local/build/httpd-2.0.45
~>
sudo make
===>
src
make[1]:
Entering directory `/usr/local/build/httpd-2.0.45'
make[2]: Entering directory `/usr/local/build/httpd-2.0.45/src'
===>
src/regex
sh ./mkh -p regcomp.c >regcomp.ih
…
If
you have followed our instructions for securing the host, you will have to
unpack the distribution and compile it on a separate host. To make your server more secure, use a
separate disk partition for your web content. Create a unique mount point for
this directory -- htdocs is a good name to use, but
make it somewhere outside the ServerRoot directory. You'll need to
update /etc/vfstab to mount this partition as part of your server's
startup process.
Do not use the htdocs
directory included in the distribution as your DocumentRoot.
This directory contains user documentation that you don't want to make
available to the public as it contains information a potential attacker could
use to penetrate your system. (The attacker can deduce what kind of web server
you’re running, and hone his attack accordingly.) Move these documentation files into your support
directory so the webmasters for your site can refer to them as needed.
You’ll
need to install the Apache server using “sudo”
privileges or as root.
~> pwd
/usr/local/build/httpd-2.0.45
~> sudo
make install
===> [mktree: Creating Apache installation tree]
./src/helpers/mkdir.sh
/opt/apache2/bin
./src/helpers/mkdir.sh
/opt/apache2/libexec
./src/helpers/mkdir.sh
/opt/apache2/man/man1
./src/helpers/mkdir.sh
/opt/apache2/man/man8
./src/helpers/mkdir.sh
/opt/apache2/conf
..
Now
that the server is installed, we need to copy certificate key, server
certificate, and CA chain to Apache’s configuration directory.
~> pwd
/opt/apache2/conf
~> sudo
mkdir ssl.crt ssl.key
~> sudo
cp /usr/local/build/server.crt ./ssl.crt/.
~>
sudo cp /usr/local/build/server.key
./ssl.key/.
Configure
the file permissions and runtime settings of the Apache server. It’s important that you place your htdocs, cgi-bin, and logs
directories on separately mounted filesystems.
Set
the following in your httpd.conf file. You can also download an example httpd.conf with these settings here.
Directive and setting
|
Description/rationale
|
|
ServerSignature
Off |
Prevents
server from giving version info on error pages. |
|
ServerTokens
Prod |
Prevents
server from giving version info in HTTP headers |
|
Listen 80 (remove) |
Remove the “Listen” directive – we’ll set this
directive only in ssl.conf, so that it will only be
available over https. |
|
User webserv (or
whatever you created in step 2 above) |
Ensure
that the child processes run as unprivileged user |
|
Group webserv (or
whatever you created in step 2 above) |
Ensure
that the child processes run as unprivileged group |
|
ErrorDocument 404
errors/404.html ErrorDocument 500
errors/500.html etc. |
To
further obfuscate the web server and version, this will redirect to a page
that you should create, rather than using the default Apache pages. |
|
ServerAdmin
<hostname>-webmaster@xianco.com |
Use
a mail alias – never use a person’s email address here. |
|
UserDir disabled root |
Remove
the UserDir line, since we disabled this module. If you do enable user directories, you’ll
need this line to protect root’s files. |
|
<Directory /> Order
Deny, Allow deny
from all </Directory> |
Deny
access to the root file system. |
|
<Directory /opt/apache2/htdocs"> <LimitExcept deny
from all </LimitExcept>
Options -FollowSymLinks -Includes
-Indexes -MultiViews AllowOverride None Order allow,deny Allow from
all </Directory> |
LimitExcept
prevents TRACE from allowing attackers to find a path through cache or proxy
servers. The “-“ before any directive disables that
option. FollowSymLinks allows a user to navigate
outside the doc tree, and Indexes will reveal the contents of any directory
in your doc tree. Includes allows .shtml pages,
which use server-side includes (potentially allowing access to the
host). If you really need SSI, use IncludesNoExec instead. AllowOverride
None will
prevent developers from overriding these specifications in other parts of the
doc tree. |
|
AddIcon
(remove) IndexOptions
(remove) AddDescription
(remove) ReadmeName
(remove) HeaderName
(remove) IndexIgnore
(remove) |