Showing posts with label Apache. Show all posts
Showing posts with label Apache. Show all posts

January 24, 2008

Securing Apache 2 Step-by-Step

When choosing a web server, Apache very often wins against its competitors because of stability, performance, that fact that it's open source, and many other advantages. But when deciding on which version of Apache to use, the choice is not always so simple. On the one hand there is a very popular, stable version used by millions of users, version 1.3, and on the other hand, there is an enhanced and re-designed version 2.0.
And even if the new version has got a lot more extensions and features, some people still decide to use version 1.3, because in their opinion this branch is more stable and secure. As a matter of fact, there is some truth in this statement. Since version 1.3 has been used by millions of users for a long time, most security holes in this version are very likely to be already discovered. At the same time version 2.0 may have many more as-yet undiscovered vulnerabilities, just sleeping and waiting to be found.
Continuing the step-by-step fashion from the previous series (Securing Apache, Securing PHP, and Securing MySQL), this article shows how to install and configure Apache 2.0 to minimize the risk of unauthorized access or successful break-in, even if new security vulnerabilities in Apache web server are found. Thus, it will be possible to enjoy the new features of Apache 2.0 without worrying too much about its security bugs, regardless if they are only imaginary, or are in fact real and serious threats.
Functionality requirements
In the world of security, there are a few golden principles that should always be followed. One such principle is the rule which says that only absolutely required parts of the software should be used. All other components should be disabled, made inaccessible or not even be installed at all.
The logic behind this rule is very simple -- if there is software with dozens of components that are enabled by default, finding only one security vulnerability in any one of these components can put the whole system at risk of a successful break-in. On the other hand, if only a few absolutely necessary components are enabled, finding a new security bug doesn't necessary mean that the software is vulnerable -- because the discovered bug may affect components that are not enabled, or are not installed. The probability of a successful break-in in this case is obviously much lower than in case of the default installation.
Therefore, before starting to secure Apache 2, it is very important to know what functionality we really expect from the web server. This will allow us to prepare the list of modules that we will leave enabled, while the rest will be disabled during compilation time.
According to this rule, this article assumes that very basic functionality of Apache will be used:
• Only static HTML pages will be served.
• The server must support the virtual hosting mechanism.
• Access to some web pages will be restricted to selected IP addresses or users (basic authentication).
• The server must log all web requests (including information about web browsers).
One can note that the above functionality doesn't support CGI scripts, the SSL protocol or other useful Apache features. This is because the main purpose of the article is to present a general method of securing Apache 2.0, without focusing on a particular implementation. If there is a need for additional functionality, readers can still use the presented solution as a starting point, and enhance it by enabling additional modules, for example, mod_ssl, mod_cgi or others.
Security assumptions
To provide as many security layers as possible, and at the same time keep this solution portable among many different Linux/BSD systems, the following layers of security will be used:
the network environment
• The web server should be protected by a firewall; the rules should accept incoming requests to port 80/tcp and allow outgoing HTTP responses. Except for certain ICMP messages (e.g. source-quench, time-exceed, parameter-problem, destination-unreachable), all other packets should be dropped or denied.
• An intrusion detection (or prevention) system should be used; Apache's log files should also be monitored.
the operating system
• The operating system should be hardened as much as possible; all unnecessary components should be removed from the system.
• If supported, the operating system should not allow executing programs on the stack.
• All unnecessary network services should be disabled.
• The number of SUID/SGID files should be minimized.
the Apache web server
• Only absolutely necessary Apache modules should be enabled; the rest should be disabled during compilation time.
• All diagnostic web pages and the automatic directory indexing service must be turned off.
• The server should disclose the least amount of information about itself as possible -- security through obscurity. Although this is not a real security layer, applying it will at least make the attacks a little bit more difficult to perform.
• The web server must run under a dedicated UID/GID, not one used by any other system process.
• Apache's processes must have limited access to the file systems (chrooting).
• In the Apache chrooted environment there cannot be any shell program present (/bin/sh, /bin/csh etc.) -- it makes the process of executing exploits much more difficult to perform.
Installing the operating system
First and foremost, we must choose an operating system upon which the web server will run. The rest of article presents how to secure Apache on FreeBSD (5.1), however readers are free to use their favorite Unix, BSD, Linux or Linux-like operating system.
With regards to our security assumptions, after installing the operating system it must be hardened against both remote and local attacks. Regardless of the chosen UNIX/Linux/BSD distribution, it is very important to install only the core operating system, remove any redundant packages and apply up-to-date patches to the kernel and all installed software.
It is also recommended to periodically synchronize the local clock against a trusted time server, using the Network Time Protocol (NTP), and to send log files to a remote, dedicated log server.
After the system is prepared, we can start installing Apache 2.0. The first step is to add a new group and regular user called apache. An example from FreeBSD has been shown below:
pw groupadd apache
pw useradd apache -c "Apache Server" -d /dev/null -g apache -s /sbin/nologin
The Apache child processes will run with the privileges of the group and user apache. Since the above account will be dedicated to the Apache web server, this will provide separation of privileges and avoid potential security problems when several different processes are being run under the same account, e.g. user nobody.
Downloading the software
Next, the latest version of Apache 2.0 software should be downloaded from the Apache website, and then unpacked. Since we want to disable unnecessary modules during compilation time, it is very important to download the source code, not binaries. It is also important to test the downloaded software against a PGP signature, to make sure that the downloaded version is complete and unmodified.
lynx http://httpd.apache.org/download.cgi

gpg --import KEYS
gpg httpd-2.0.49.tar.gz.asc
gpg: Good signature from "Sander Striker "
tar zxvf httpd-2.0.49.tar.gz
cd ./httpd-2.0.49/
Choosing Apache's modules
After the Apache source code is unpacked, we must choose which modules will remain enabled, and which will be removed. A short description of all modules available in Apache 2.0 can be found at http://httpd.apache.org/docs-2.0/mod/.
To fulfill the functionality and security requirements assumed at the beginning of this article, we will compile only the following modules:
Module's name Description
core The core Apache features, required in every Apache installation.
http_core The core http support, required in every Apache 2.0 installation.
prefork Multi-Processing Module (MPM) that implements a non-threaded, pre-forking web server. Can be replaced by other multiprocessing module, e.g. worker , threadpool etc. The MPM module is required in every Apache 2.0 installation.
mod_access Provides access control based on client hostname, IP address, or other characteristics of the client request. Because this module is needed to use "order", "allow" and "deny" directives, it should remain enabled.
mod_auth Required in order to implement user authentication using text files (HTTP Basic Authentication), which was specified in functionality assumptions.
mod_dir Required to search and serve directory index files: "index.html", "default.htm", etc.
mod_log_config Required to implement logging of the requests made to the server.
mod_mime Required to set the character set, content- encoding, handler, content-language, and MIME types of documents.
Since we want to enable only the minimal number of modules, we will compile all the modules statically. Thanks to that, we will eliminate possibility of occurring vulnerabilities in one more module -- mod_so.
Compiling and installing the software
In this step we will configure, compile, and install the Apache web server as follows:
./configure \
--prefix=/usr/local/apache2 \
--with-mpm=prefork \
--disable-charset-lite \
--disable-include \
--disable-env \
--disable-setenvif \
--disable-status \
--disable-autoindex \
--disable-asis \
--disable-cgi \
--disable-negotiation \
--disable-imap \
--disable-actions \
--disable-userdir \
--disable-alias \
--disable-so
make
su
umask 022
make install
chown -R root:sys /usr/local/apache2
After Apache is installed, we should make sure that only the following modules are enabled:
/usr/local/apache2/bin/httpd -l
Compiled in modules:
core.c
mod_access.c
mod_auth.c
mod_log_config.c
prefork.c
http_core.c
mod_mime.c
mod_dir.c
Configuring Apache
Before running Apache for the first time, we also need to modify the Apache configuration file. We need to do this because the default configuration file uses modules that we disabled, and without modifications Apache will not run.
Thus, we must remove the /usr/local/apache2/conf/httpd.conf file and create a new httpd.conf in its place, with the following content:
# =================================================
# Basic settings
# =================================================
Listen 0.0.0.0:80
User apache
Group apache
ServerAdmin webmaster@www.ebank.lab
UseCanonicalName Off
ServerSignature Off
HostnameLookups Off
ServerTokens Prod
ServerRoot "/usr/local/apache2"
DocumentRoot "/www"
PidFile /usr/local/apache2/logs/httpd.pid
ScoreBoardFile /usr/local/apache2/logs/httpd.scoreboard

DirectoryIndex index.html


# =================================================
# HTTP and performance settings
# =================================================
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 15

MinSpareServers 5
MaxSpareServers 10
StartServers 5
MaxClients 150
MaxRequestsPerChild 0


# =================================================
# Access control
# =================================================

Options None
AllowOverride None
Order deny,allow
Deny from all


Order allow,deny
Allow from all


Order allow,deny
Allow from all


# =================================================
# MIME encoding
# =================================================

TypesConfig /usr/local/apache2/conf/mime.types

DefaultType text/plain

AddEncoding x-compress .Z
AddEncoding x-gzip .gz .tgz
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType application/x-tar .tgz


# =================================================
# Logs
# =================================================
LogLevel warn
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
ErrorLog /usr/local/apache2/logs/error_log
CustomLog /usr/local/apache2/logs/access_log combined

# =================================================
# Virtual hosts
# =================================================
NameVirtualHost *

DocumentRoot "/www/www.ebank.lab"
ServerName "www.ebank.lab"
ServerAlias "www.e-bank.lab"
ErrorLog logs/www.ebank.lab/error_log
CustomLog logs/www.ebank.lab/access_log combined


DocumentRoot "/www/www.test.lab"
ServerName "www.test.lab"
ErrorLog logs/www.test.lab/error_log
CustomLog logs/www.test.lab/access_log combined

Compared to the default configuration file, the following important changes have been made:
• The number of enabled modules has been reduced to minimum.
• Apache's processes (except for the root process) are set to be executed with unique regular user/group privileges.
• Apache discloses the least information about itself as possible.
• Access rights to the website's content are set to be more restrictive.
According to our functionality requirements, the above configuration assumes that there are two virtual hosts supported by Apache:
• www.ebank.lab (alias: www.e-bank.lab)
• www.test.lab
The content of the above virtual hosts will be physically kept under the /www directory, so before running Apache we also need to create the corresponding directories with sample web pages:
mkdir -p /www/www.ebank.lab
mkdir -p /www/www.test.lab
echo "eBank.lab
works!" > /www/www.ebank.lab/index.html
echo "Test.lab
works!" > /www/www.test.lab/index.html
chmod -R 755 /www
chown -R root:sys /www
We must also prepare directories for storing our log files:
mkdir -p /usr/local/apache2/logs/www.ebank.lab
mkdir -p /usr/local/apache2/logs/www.test.lab
chmod -R 755 /usr/local/apache2/logs
chown -R root:sys /usr/local/apache2/logs
Finally, we can try to run Apache, and test if everything works properly:
/usr/local/apache2/bin/apachectl start
If the www.ebank.lab website is accessible from a web browser, we can shutdown Apache:
/usr/local/apache2/bin/apachectl stop
and then proceed to chroot the server. If there are problems, log files should be analyzed, or the truss command (for BSD and Solaris users) should be used, as follows:
truss /usr/local/apache2/bin/httpd
Note that for Linux users, the equivalent command is strace. Either way, analyzing the output of the truss (or strace) command should help with finding the reason of failure.
Chrooting the server
The next step is to limit the Apache processes' access to the filesystems. The chrooting technique was described in detail in the previous article, so at this point we will simply create a directory structure for our new Apache:
mkdir -p /chroot/httpd/dev
mkdir -p /chroot/httpd/etc
mkdir -p /chroot/httpd/var/run
mkdir -p /chroot/httpd/usr/lib
mkdir -p /chroot/httpd/usr/libexec
mkdir -p /chroot/httpd/usr/local/apache2/bin
mkdir -p /chroot/httpd/usr/local/apache2/lib
mkdir -p /chroot/httpd/usr/local/apache2/logs/www.ebank.lab
mkdir -p /chroot/httpd/usr/local/apache2/logs/www.test.lab
mkdir -p /chroot/httpd/usr/local/apache2/conf
mkdir -p /chroot/httpd/usr/local/lib
mkdir -p /chroot/httpd/www
The owner of all the above directories should be root, and access rights should not allow regular users to perform any changes in these directories:
chown -R root:sys /chroot/httpd
chmod -R 0755 /chroot/httpd
Next, we will create the special device file, /dev/null:
ls -al /dev/null
crw-rw-rw- 1 root wheel 2, 2 Mar 14 12:53 /dev/null
mknod /chroot/httpd/dev/null c 2 2
chown root:sys /chroot/httpd/dev/null
chmod 666 /chroot/httpd/dev/null
We also need to create a /chroot/httpd/dev/log device that is needed for the server to work properly. In the case of our FreeBSD system, the following line should be added to /etc/rc.conf :
syslogd_flags="-l /chroot/httpd/dev/log"
In order for the changes to take effect, we also need to restart the syslogd daemon with the new parameter:
kill `cat /var/run/syslog.pid`
/usr/sbin/syslogd -ss -l /chroot/httpd/dev/log
The next step is to copy all necessary programs, libraries and configuration files into the new directory tree. In the case of FreeBSD 5.1 the list of required files is as follows:
cp /usr/local/apache2/bin/httpd /chroot/httpd/usr/local/apache2/bin/
cp /usr/local/apache2/lib/libaprutil-0.so.9 /chroot/httpd/usr/local/apache2/lib/
cp /usr/local/apache2/lib/libapr-0.so.9 /chroot/httpd/usr/local/apache2/lib/
cp /usr/local/apache2/conf/mime.types /chroot/httpd/usr/local/apache2/conf/
cp /usr/local/apache2/conf/httpd.conf /chroot/httpd/usr/local/apache2/conf/
cp /usr/local/lib/libexpat.so.4 /chroot/httpd/usr/local/lib/
cp /usr/lib/libc.so.5 /chroot/httpd/usr/lib/
cp /usr/lib/libcrypt.so.2 /chroot/httpd/usr/lib/
cp /usr/lib/libm.so.2 /chroot/httpd/usr/lib/
cp /usr/libexec/ld-elf.so.1 /chroot/httpd/usr/libexec/
cp /var/run/ld-elf.so.hints /chroot/httpd/var/run/
cp /etc/hosts /chroot/httpd/etc/
cp /etc/nsswitch.conf /chroot/httpd/etc/
cp /etc/resolv.conf /chroot/httpd/etc/
cp /etc/group /chroot/httpd/etc/
cp /etc/master.passwd /chroot/httpd/etc/passwords
In the case of other Unix, BSD, Linux and Linux-like systems, the list of required files can be determined by using commands like ldd, strace, truss or strings, as was described in the previous article.
After the above steps are done, we need to prepare the password database that must be present in the chrooted filesystem. Thus, from /chroot/httpd/etc/passwords and /chroot/httpd/etc/group we have to remove all the lines except apache. Next, we should build the password database as follows:
cd /chroot/httpd/etc
pwd_mkdb -d /chroot/httpd/etc passwords
rm -rf /chroot/httpd/etc/master.passwd
The above commands should be executed when using FreeBSD. In other systems it may be sufficient to edit the /chroot/httpd/etc/passwd and /chroot/httpd/etc/shadow files.
Finally, we can copy the sample website content to the chrooted environment:
cp -R /www/* /chroot/httpd/www/
and test if the Apache web server runs correctly:
chroot /chroot/httpd /usr/local/apache2/bin/httpd
Final steps
If your Apache now works properly, the only thing that is left to do is to create a script that will start Apache during system boot. In order to do this, the apache.sh script can be used, with the following content:
#!/bin/sh
CHROOT=/chroot/httpd
HTTPD=/usr/local/apache2/bin/httpd
PIDFILE=/usr/local/apache2/logs/httpd.pid

echo -n " apache"

case "$1" in
start)
/usr/sbin/chroot $CHROOT $HTTPD
;;
stop)
kill `cat ${CHROOT}/${PIDFILE}`
;;
*)
echo ""
echo "Usage: `basename $0` {startstop}" >&2
exit 64
;;
esac

exit 0
The above script should be copied to the directory where by default startup scripts are held. In the case of FreeBSD it is the /usr/local/etc/rc.d directory. The access rights to that file should be set as follows:
chown root:sys /usr/local/etc/rc.d/apache.sh
chmod 711 /usr/local/etc/rc.d/apache.sh
Summary
The main goal of this article was to present a method of securing Apache 2.0 that lets readers mitigate the risk of a successful break-in, even if new vulnerabilities in this software are found. It has been shown how to install Apache with a minimal number of modules, how to set up a more restrictive configuration, and how to implement protection against a large number of exploits by running the web server in a chrooted environment, without the use of any shell programs. And although no method can assure a 100% security, applying the above recommendations will at least make performing a web attack against Apache 2.0 much more difficult, as compared to the default installation.


Relevant links
Securing Apache: Step-by-Step: http://www.securityfocus.com/infocus/1694
Securing PHP: Step-by-Step: http://www.securityfocus.com/infocus/1706
Securing MySQL: Step-by-Step: http://www.securityfocus.com/infocus/1726
Apache HTTP Server Project: http://httpd.apache.org
Sample httpd.conf: httpd.conf
Sample apache.sh: apache.sh

About the author
Artur Maj works as a Principal Software Engineer for Oracle Corporation, in the EMEA Mobile, Wireless & Voice Center of Expertise. He is experienced in designing computer systems, performing security audits as well as providing security training. He is also author of many articles and publications devoted to securing computer systems and software against intruders.

Apache 2 with SSLTLS Step-by-StepPart 3

Introducing part three
This article concludes our three part series dedicated to configuring Apache 2.0 with SSL/TLS support -- for maximum security and optimal performance of SSL based e-commerce transactions.
Part one introduced key aspects of SSL/TLS and then showed how to compile, install and configure Apache 2.0. The second part discussed the configuration of mod_ssl and authentication issues, and then showed how to create web server's SSL certificate.
Now, in the third and final article, we will take a look at client authentication using client certificates, show how to chroot a secure Apache, discuss common attack vectors, and then describe some typical configuration mistakes made by administrators that will decrease the security level of SSL communications.
Client authentication
One of the most popular methods for authenticating users in web applications is a password, passphrase or PIN, in other words, "something you know." The greatest advantage of such a method is its simplicity. For an administrator, it is enough to add few directives to httpd.conf and create a passwd file to implement such a schema.
Unfortunately, because of their simplicity passwords are vulnerable to a number of attacks. They can be guessed, sniffed over the wire, brute-forced, stolen (such as when a user writes them down on sticky notes) or coaxed out (through social engineering or some kind of "phishing" method). This is why standard password authentication is considered to be weaker than using one-time passwords, hardware tokens or others forms of authentication.
Few people realize that when using a SSL web server there is an stronger method of authenticating users: client SSL certificates, or "personal" certificates for each user. In this method, we can authenticate web users based on "something you have," using a certificate and a private key corresponding to the client certificate, as well as "something you know," which would be a passphrase to the private key. Thus, using certificates is more secure than using standard password solutions, mainly because besides an intruder would need to get both pieces of authentication -- the private key that corresponds to the user's certificate, as well as the passphrase -- to gain access. Moreover, unlike a standard password, the certificate's passphrase is not actually sent over the network at all, it is used only locally to decrypt the private key.
As will be shown, the implementation of this method of authentication is not complicated and it can be performed in few steps, which administrators will find to be almost as easy as the more popular Basic Authentication password method.
Configuring Apache to use client certificates
In order to configure Apache to support client authentication via X.509v3 certificates, we need to perform four actions:
1. Enable client authentication in the Apache's web server
To enable the use of client certificates, we need to add the following directives to httpd.conf:
SSLVerifyClient require
SSLVerifyDepth 1
Thanks to the SSLVerifyClient directive, the access to the web server will now be limited only to the web browsers that present a valid certificate, one which is signed by our local CA. Note that the process of creating local CA has been described in the previous article. The "SSLVerifyDepth" value specifies the maximum depth of the intermediate certificate issuers in the chain of certificates. In our case, we will set this value to "1," because all client certificates must be signed by our local CA -- we are not using intermediate CAs.
2. Install the local CA's certificate into the Apache directory structure.
install -m 644 -o root -g sys ca.crt /usr/local/apache2/conf/ssl.crt/
3. Set the SSLCACertificateFile directive (in httpd.conf) to point to the CA certificate we just installed.
SSLCACertificateFile /usr/local/apache2/conf/ssl.crt/ca.crt
4. Now restart Apache.
/usr/local/apache2/bin/apachectl stop
/usr/local/apache2/bin/apachectl startssl
From now on, access to the web server via SSL will be granted only to the web browsers that present a valid client certificate, signed by our local CA. To test it, we can try to access the URL of the website. After establishing SSL connection, MS Internet Explorer will ask us to choose the client certificate we want to use, as shown below in Figure 1.

Figure 1. Internet Explorer asking for a client certificate.
Since we do not yet have any client certificate installed, access to the web server will simply be denied.
Creating a client certificate
In general, creating an individual client certificate is very similar to creating a web server certificate. The only difference is that we will use different X.509v3 extensions (the "ssl_client" section from openssl.cnf) and we will store both the private key and certificate in PKCS#12 format (also referred as PFX).
For the sake of simplicity, please follow the steps below using OpenSSL to produce the client certificate. Note that it is highly recommended that any actions that are to be performed by users (numbers 1, 2, 7, 8 in the steps below) should be as automated and simplified as possible to minimize user interaction and user error. To that end, additional technology such as Java Applets could be used. Alternatively, a dedicated host can also be used for the purpose of creating client certificates. In this latter case, users would need to visit the server in-person and enter their passphrase on the dedicated host to encrypt their own private key. Although this option might seem a bit inconvenient, it is the most secure method, as a user's identity can be verified and both the certificate and the private key can be passed to the user without sending it over the network.
The steps to create and install a client certificate are exactly as follows:
1. Create a private/public key pair for the user, together with a certificate request. If a dedicated host is not being used to serve the certificate, this should be executed on the user's host:
openssl req \
-new \
-sha1 \
-newkey rsa:1024 \
-nodes \
-keyout client.key \
-out request.pem \
-subj '/O=Seccure/OU=Seccure Labs/CN=Frodo Baggins'
2. The user sends the certificate request (request.pem) to the local CA, to be signed.
3. The local CA's task is to verify that the information from the client certificate request is indeed valid and correct.
4. After verifying, the certificate request (request.pem) should be copied into the $SSLDIR/requests directory on the local CA host using removable media, such as a USB drive.
5. The local CA should sign the certificate request as follows. This should be executed on the CA's host.
openssl ca \
-config $SSLDIR/openssl.cnf \
-policy policy_anything \
-extensions ssl_client \
-out $SSLDIR/requests/signed.pem \
-infiles $SSLDIR/requests/request.pem
6. The local CA should send the certificate (signed.pem) to the user.
7. After receiving the signed certificate, users need to store their private key together with their certificate into PKCS#12 format.
openssl pkcs12 \
-export \
-clcerts \
-in signed.pem \
-inkey client.key \
-out client.p12
8. The newly created client.p12 file should be protected with a hard-to-guess passphrase. All other files (including the unencrypted private key, the signed certificate and the certificate request) should be securely erased from the user's disk space using a wipe utility.
wipe client.key signed.pem request.pem
9. The client certificate, together with the private key, should be installed in the user's web browser. An example of this for Microsoft Internet Explorer is shown below in Figure 2.

Figure 2. Installing a certificate in Internet Explorer.
To protect the private key against accidental or unauthorized use, the option "Enable strong private key protection" should be checked. Also, to protect the certificate from being stolen, it should be not be possible to export the certificate -- the option "Mark this key as exportable" should be disabled. Both these browser configuration options are shown below in Figure 3.

Figure 3. Protecting the client certificate in Internet Explorer.
In addition, the security level of the browser should be changed to "High." We see this during the next step of the Import Wizard, as illustrated below in Figure 4. Thanks to this option, a user will be asked to enter his password every time the web browser wants to use that client certificate.

Figure 4. Security level should be set to "High" in IE.
That's all there is to it. The certificate can now be found under the "Personal" tab in the certificate view (in MS Internet Explorer's menu -> tab "Content" -> "Certificates"). If we double click the certificate we should see some properties similar to Figure 5, below.

Figure 5. Client certificate details in IE.
Using the client certificate
At this point we should try to access the URL of the website again. If the above have been successfully completed, once it is requested we should be able to see and choose the installed certificate from the list, as shown in Figure 6.

Figure 6. Choosing the client certificate when prompted.
After choosing the certificate, the user must enter the required passphrase that decrypts the corresponding private key, as shown in Figure 7.

Figure 7. Entering the passphrase for the certficate.
Now we will have access to the secure website, illustrated in Figure 8.

Figure 8. Secure access, using certificates, has been granted.
Customizing access control
With additional server-side directives, we can control which parts of the website particular users or groups of users are granted or denied access. For example, when and organization must deal securely with many different companies, we can restrict access to the website to just one particular company (O=Seccure), by adding the following directives to httpd.conf:

SSLRequire %{SSL_CLIENT_S_DN_O} eq "Seccure"

Another example shows how to allow access only to a certain department (OU="Seccure Labs") within the company (O="Seccure"):
SSLRequire %{SSL_CLIENT_S_DN_O} eq "Seccure" and \
%{SSL_CLIENT_S_DN_OU } eq "Seccure Labs"
Or alternatively, we can provide access to just a few departments (OU="Seccure Labs" or OU="Development") within the same company (O="Seccure"):
SSLRequire %{SSL_CLIENT_S_DN_O} eq "Seccure" and \
%{SSL_CLIENT_S_DN_OU } in {"Seccure Labs", "Development"}
Finally, we can even provide access to just one specific user (CN="Frodo Baggins") from a specific company (O="Seccure"):
SSLRequire %{SSL_CLIENT_S_DN_O} eq "Seccure" and \
%{SSL_CLIENT_S_DN_CN} in {"Frodo Baggins"}
Note that we can also provide the above environment variables to CGI scripts (including PHP and others), by adding the "+StdEnvVars" parameter to the SSLOptions directive. This features allows us to use DN names inside web applications (PHP and others), to provide more detailed authorization and access control.
SSLOptions +StdEnvVars
Revoking a client certificate
If a client certificate becomes compromised or lost, what do you do? In this case we need to revoke the certificate, as was already described in the previous article. Then, we must copy the CRL file into the Apache directory, as follows:
install -m 644 -o root -g sys crl.pem /usr/local/apache2/conf/ssl.crl/
We also need to make sure that the "SSLCARevocationFile" in httpd.conf points to the above file:
SSLCARevocationFile /usr/local/apache2/conf/ssl.crl/crl.pem
Then, we need to restart Apache for the changes to take an effect. The revoked certificates will not be allowed access to the website, as shown below in Figure 9.

Figure 9. Access attempted with a revoked certificate.
Chrooting the server
To improve our web server's security and make Apache less vulnerable to buffer overflow attacks, it is recommended that one run Apache in the chrooted environment. Chrooting the web server isolates the process to a new root directory so that it cannot see the rest of the server's files.
The process of chrooting Apache has been already described in "Securing Apache 2.0: Step-by-Step," so readers are encouraged to follow steps that were shown there. With the added support for SSL/TLS, we will need to install some additional libraries and create a few new subdirectories. In the case of FreeBSD 5.1, the list of these libraries and directories are as follows:
cp /usr/lib/libssl.so.3 /chroot/httpd/usr/lib/
cp /usr/lib/libcrypto.so.3 /chroot/httpd/usr/lib/
cp -R /usr/local/apache2/conf/ssl.key /chroot/httpd/usr/local/apache2/conf/
cp -R /usr/local/apache2/conf/ssl.crt /chroot/httpd/usr/local/apache2/conf/
cp -R /usr/local/apache2/conf/ssl.crl /chroot/httpd/usr/local/apache2/conf/
We also need to add urandom device as follows. Once again, the example below is taken from FreeBSD 5.1:
ls -al /dev/*random
crw-rw-rw- 1 root wheel 2, 3 Jan 4 12:10 /dev/random
lrwxr-xr-x 1 root wheel 7 Jan 4 12:10 /dev/urandom -> random
cd /chroot/httpd/dev
mknod ./random c 2 3
ln -s ./random ./urandom
chown root:sys ./random
chmod 666 ./random
In the case of other operating systems, readers can create the list of required files by using commands like truss, strace, ktrace etc., as was described in details in the section "Chrooting the server," from the SecurityFocus article, "Securing Apache: Step-by-Step"
Once all these steps have been completed, we can run Apache in the chrooted environment, as follows:
chroot /chroot/httpd /usr/local/apache2/bin/httpd
Known attacks on SSL/TLS
Although SSL/TLS protocols offer a high level of security in theory, its actual implementations may be vulnerable to several types of attacks. Of the many attack vectors, two are worthy of special attention:
• Man in the middle (MITM) attacks
In this type of attack, an intruder intercepts the traffic that is being sent between a client and server, such as by forging DNS replies or by performing ARP redirection. Then, it impersonates the client to the server, and vice-versa. During this attack, the user's web browser does not connect directly to the destination server, but instead to the intruder host, which impersonate the web browser and essentially acts as a proxy.
There is good and bad news for an administrator who wishes to defend against such attacks. The good news is that the web browsers warn users when the web server's identity cannot be verified, which may indicate possible man-in-the-middle attack, by displaying a message window with a warning. The bad news is that in real life, users very often ignore such warnings. Hence, if the user's web browser accepts connections to SSL web sites that identities cannot be checked, we can only rely on users' education and trust that they will not press the "proceed" button, if such warning message has been displayed.
• Brute-force attack on the session key
This attacks can be performed when the intruder knows or can assume part of the clear text that was sent during SSL/TLS session, such as (such as "GET / HTTP/1.0"), and the intruder can eavesdrop this session (such by using tcpdump, Ethereal or other tools). Then, intruder can encrypt the assumed part of the text by using every possible key, trying to find its occurrence in the originally encrypted SSL/TLS traffic. Once such an occurrence has been found, the key that was used to encrypt this part of the message can be used to decrypt the rest of originally encrypted SSL/TLS traffic.
The good news is that maximum number of keys that must be checked is 2^128 when 128-bit symmetric cryptography has been used. Today this is believed to be strong enough to protect the session for literally dozens of years. However, since CPUs grow in strength every year, we cannot really predict for how long 128-bit symmetric keys will be considered to be secure, particularly for hackers with access to large supercomputers.
In case of export-class cipher suites (40-bit, and in some extended 56-bit ciphers) such brute force attacks can be successfully performed in a reasonable amoung of time -- sometimes even in few days, depending on the available number of CPUs. If export regulations in your country allow for the use of strong cryptography, one should definitely use it instead of export-class cipher suites.
In addition to the two types of attacks listed above, there are some other potential vulnerabilities, including algorithm rollback attacks, timing attacks, traffic analysis, Bleinchenbacher's attacks, and others. Those interested in understanding them can find more information in Bruce Schneier and David Wagner's document, "Analysis of the SSL 3.0 protocol," (PDF document) as well as in many other documents that can be found on the public Internet.
Typical SSL/TLS implementation mistakes
• Certificates signed by a CA that is not known to the web browser
The biggest mistake that can be made when implementing SSL/TLS is with the signing of the web server's certificate by a CA that is not trusted by web browser. In other words, the CA's certificate is not installed in the web browser. This makes Man-In-The-Middle attacks very easy to perform, because users have no way of verifying the identity of the web server.
To avoid this problem, it is important to make sure that signer's certificate (usually, a trusted CA) is installed in user's web browser. If a local CA was used for signing the web server's certificate, then we must make sure that all web browsers on all clients requiring access have the local CA's certificate installed. The same rule applies to self-signed certificates.
• Expired certificates
The web browser's certificate should be renewed before the previous one expires. Otherwise it will result in the same problem as above, whereby web clients will not be able to authenticate with the web server -- which once again makes SSL/TLS connections vulnerable to man in the middle attacks. In this case, users may get used to seeing a warning message saying the certificate has expired, and then will probably not notice if it is a bogus certificate.
• Vulnerable versions of OpenSSL and Apache
It is very important to always run the latest versions of OpenSSL and Apache. Programmers writing larger pieces of code such as these without bugs is virtually impossible, so we should always use the latest stable versions of the above software. The latest versions should theoretically contain fewer security vulnerabilities (both discovered and not-yet discovered) than previous versions.
• Acceptance of SSL v2.0, anonymous authentication (aNULL), and cryptography (NULL) by the web server
As was previously discussed, the use of cipher suites that support anonymous authentication or require no encryption should be disabled. Otherwise, there is a risk that client can be tricked into negotiating parameters that can dramatically lower the security level of the connection. For this reason we should disable the use of the SSLv2.0 protocol and use TLSv1.0 or SSLv3.0 instead.
• Use of weak encryption
Early implementations of SSL were only able to use 40-bit keys for symmetric encryption, due to US government restrictions. Unfortunately, the data encrypted by 40-bits symmetric keys can now be decrypted in a relatively short period of time, and for this reason 40-bit and 56-bit keys should no longer be used. Most modern web browsers support 128-bit keys for symmetric encryption, and this is now the minimal recommended length of key for use with SSL/TLS.
• Improper use of a Network Intruder Detection System (NIDS)
It is important to stress that unless a NIDS is capable of decrypting the SSL traffic (such as through the use of the web server's private key) it is simply unable to detect attacks on the web application. To detect eventual break-ins, we must either use either a HIDS (Host-based Intruder Detection System), or put the NIDS in a segment where SSL/TLS traffic is being sent in clear text, such as between a SSL Reverse Proxy and the web server's farm. Otherwise we may not be able to detect any attacks, except denial of service, performed against the web server.
• Allowing access not only via SSL, but also via non-encrypted protocols (HTTP)
Setting up SSL/TLS and opening port 443/tcp to the web server, by itself, means nothing if users can still access website via non-encrypted HTTP on port 80/tcp. Thus, one must double-check that the protected content cannot be accessed via non-encrypted HTTP or other protocols (including FTP, Samba, NFS, and so on).
• Vulnerable client machines
When we focus on securing Apache web servers, we can easily forget about the security of the client machines. If they are compromised, the security of SSL/TLS is compromised as well. In that case, intruders could do as they like with client hosts, such as replace certificates in web browsers, install keyloggers, change /etc/hosts to redirect web requests to bogus web servers, or even steal client certificates if they they have been marked as "exportable."
Therefore, if the client machines are under our administrative domain, we need to take great care with their security. Enabling a personal firewall, antivirus/antispyware software, and turning on automatic Windows updates should be the absolute minimum. Most importantly, web browser versions should be always up-to-date.
It is also recommended that one apply the following options (related to SSL/TLS) to the web browser configuration:
o checking for a publisher's certificate revocation should be enabled
o checking for any server certificate revocation should be enabled
o encrypted server pages should not be stored in the cache
o the use of SSLv2.0 should be disabled, and only TLSv1.0 and SSLv3.0 should remain enabled
o the displaying of warnings about invalid web servers certificates should be enabled
• Using the same Session IDs / cookies for SSL and HTTP
It is possible to have an Apache configuration that accepts both HTTP and HTTPS requests on the same server, such as an information website accessible via HTTP, and a transaction part accessible via HTTPS. In this case, the we must be very careful in our web application not to use the same session IDs / cookies for both protocols. Otherwise, an intruder can sniff the HTTP traffic between web server and victim, and can try to use session IDs to get access to authorized part of web application via SSL.
Conclusion
This article closes the series of articles devoted to configuring Apache 2.0 with SSL/TLS support. It has been presented how to set up SSL/TLS protocol to achieve maximum security and optimal performance. It has been also shown how to create and revoke certificates, and how to use them in practice.
Although the series has covered most important aspects of Public Key Infrastructure for use with SSL web servers, including creating, installing using and revoking certificates, we did not exhaust the subject related to PKI. On the contrary, only the real basics of PKI have been presented. Readers interested in further reading on this topic are encouraged to take a look at the documents created by the PKIX Working Group, or the OpenCA PKI Development Project, where the latter is quite a robust and open-source Certification Authority.

Relevant Links
"The TLS Protocol, Version 1.0": http://ietf.org/rfc/rfc2246.txt?number=2246
"SSL 3.0 Specification": http://wp.netscape.com/eng/ssl3/
Apache Web Server Project: http://httpd.apache.org
OpenSSL project: http://www.openssl.org
OpenCA project: http://www.openca.org
Mod_ssl website: http://www.modssl.org
Securing Apache 2: Step-by-Step: http://www.securityfocus.com/infocus/1786
PKIX Working Group: http://www.ietf.org/html.charters/pkix-charter.html
"Analysis of the SSL 3.0 protocol": http://www.schneier.com/paper-ssl-revised.pdf
"Finite-State Analysis of SSL 3.0": http://verify.stanford.edu/uli/secur/usenix/usenix.html
"Wireless Application 2.0 Security": http://www.sans.org/rr/whitepapers/wireless/159.php
Sample Apache configuration file: httpd.conf
Sample startup script: apache.sh
Sample Openssl configuration file: openssl.cnf
About the author
Artur Maj works as a Principal Software Engineer for Oracle Corporation, in the EMEA Mobile, Wireless & Voice Center of Expertise. He is experienced in designing computer systems, performing security audits as well as providing security training. He is also author of many articles and publications devoted to securing computer systems and software against intruders.

Apache 2 with SSLTLS Step-by-Step Part 2

In the first article of this three part series, the reader was shown how to install, configure, and troubleshoot Apache 2.0 with SSL/TLS support. Part two now discusses the recommended settings for the mod_ssl module that lets us achieve maximum security and optimal performance. The reader will also see how to create a local Certification Authority and a SSL certificate based on the free and open-source OpenSSL library.
Recommended settings for mod_ssl
In Apache 2.0.52, there are more than 30 directives that can be used to configure mod_ssl. The detailed description of all of them can be found in Apache's mod_ssl documentation. This section focuses only on the recommended settings which can improve the security or performance of SSL/TLS connections.
The list of these mod_ssl settings is shown below in Table 1.
Directive(s)
Recommended setting or comment
SSLEngine
Must be enabled, otherwise the main server (or virtual host) will not be using SSL/TLS
SSLRequireSSL
Must be enabled, otherwise users may be able to access the web content via regular HTTP requests, without using SSL/TLS, at all.
SSLProtocol
SSLProxyProtocol
Should be set to use only TLS v1.0 and SSL v3.0. Most of current web browsers support both of them, so we can safely disable SSL v2.0.
SSLCipherSuite
SSLProxyCipherSuite
To provide strong cryptography, this parameter should be set to use HIGH (>168 bits) and MEDIUM (128 bits) cipher suites. LOW (<56 href="http://eprint.iacr.org/2004/199.pdf">collisions . To summary, the recommended settings could be as follows:
HIGH:MEDIUM:!aNULL:+SHA1:+MD5:+HIGH:+MEDIUM
Note that it is possible to see what ciphers suites the proposed settings can support, as follows:
openssl ciphers -v 'HIGH:MEDIUM:\!aNULL:+SHA1:+MD5:+HIGH:+MEDIUM'
SSLOptions
The "+StrictRequire" options should be set, otherwise the "Satisfy Any" directive may force mod_ssl to allow access to the web content, even if SSL/TLS is not used.
SSLRandomSeed
For startup of Apache should be set to use pseudo random device (/dev/urandom) and/or EGD (Entrophy Gathering Daemon). Before establishing every new SSL connection should be configured to use built-in source, /dev/urandom or EGD. It is not recommended to use /dev/random in both cases, because /dev/random can provide only as much entropy, as it has at certain moment.
SSLSessionCache
To avoid repeating SSL handshakes for parallel HTTP requests (e.g. when web browser downloads several images at one time), SSL caching should be enabled. It should be set to use shared memory (SHM), or DBM. When setting to "none", performance of the web server may decrease significantly.
SSLSessionCacheTimeout
This value specifies the number of seconds, after which the entry in SSLSessionCache expires. It should be set to at least 300-600 seconds. However, the actual time should depend on the average time the users spent on visiting the web server. E.g., if the average time is around 15 minutes, then the value should be set to at least 900 (15 minutes * 60 seconds)
SSLVerifyClient
SSLProxyVerify
When not using client or proxy authentication, these options should be set to "none". They should never be set to "optional_no_ca", because it is against the idea of PKI authentication, where client, to be authenticated, must present valid certificate. "optional" may occasionally be used (depends on needs), however it may not work with all web browsers.
SSLVerifyDepth
SSLProxyVerifyDepth
Should contain the maximum number of intermediate CA's. E.g. to accept only self-signed certificates it should be set to zero, for client certificates that are signed by root CA - it should be 1. And so on.
SSLProxyEngine
Should be disabled, if SSL/TLS proxy mechanism is not used.
Table 1. Recommended mod_ssl settings.
Our sample settings according to the above recommendations can be shown in httpd.conf as follows:

SSLEngine on

SSLOptions +StrictRequire


SSLRequireSSL


SSLProtocol -all +TLSv1 +SSLv3

# Support only for strong cryptography
SSLCipherSuite HIGH:MEDIUM:!aNULL:+SHA1:+MD5:+HIGH:+MEDIUM
# Support for strong and export cryptography
# SSLCipherSuite HIGH:MEDIUM:EXP:!aNULL:+SHA1:+MD5:+HIGH:+MEDIUM:+EXP

SSLRandomSeed startup file:/dev/urandom 1024
SSLRandomSeed connect file:/dev/urandom 1024

SSLSessionCache shm:/usr/local/apache2/logs/ssl_cache_shm
SSLSessionCacheTimeout 600

SSLVerify none
SSLProxyEngine off
In addition to above mod_ssl directives, there are also two important directives from other Apache modules (mod_log_config and mod_set_envif) that need to be setup, as shown below in Table 2.
Directive(s)
Recommended setting / comment
CustomLog
To log information about SSL parameters (recommended minimum: the protocol version and chosen cipher suites) we should use the following value:

CustomLog logs/ssl_request_log \
"%t %h %{HTTPS}x %{SSL_PROTOCOL}x %{SSL_CIPHER}x
%{SSL_CIPHER_USEKEYSIZE}x %{SSL_CLIENT_VERIFY}x
\"%r\" %b"
Setenvif
To provide compatibility with older versions of MS Internet Explorer, which has got known bugs in SSL implementation (e.g. problems with keep-alive functionality, HTTP/1.1 over SSL, and SSL close notify alerts on socket connection close), the following option should be set:

SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
The above option will cause that web server will neither use HTTP/1.1 nor keep-alive connections, and will not send SSL close notify when the web browser is MS Internet Explorer.
Table 2. Recommended mod_log and mod_set_envif settings.
The sample configuration file (httpd.conf) presented in the previous article already includes the above settings, for the reader's convenience.
Web server authentication
Thus far we were able to configure and test SSL/TLS, but our web browser was not able to check the web server's identity. In the first article we were using a web server certificate that had been created only for testing purposes, and did not contain the information required for real authentication purposes and commerce transactions.
In order for the web browser to successfully authenticate the web server, we need to create a valid web server certificate, which should contain:
the public key of the web server
validity dates (start and expiration)
supported cipher algorithms
the distinguish name (DN), which must contain fully qualified domain name of the web server known as the Common Name (CN). Optionally it may also contain some other attributes, like Country (C), State (S), Location (L), the Organization's name (O), the Organization Unit's name (OU), and more.
the serial number of the certificate
X.509v3 attributes that will tell web browsers about the type and usage of the certificate
URI of the CRL distribution point (if exist)
URI of the X.509v3 Certificate Policy (if exist)
name and signature of trusted Certification Authority (CA)
It is important to note that the Common Name (CN) attribute must be a fully qualified domain name (FQDN) on the web server. Otherwise, the web browsers will not be able to verify if the certificate belongs to the web server that is presenting it.
A sample web server certificate (as a text representation) has been presented below.

Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: O=Seccure, OU=Seccure Root CA
Validity
Not Before: Nov 28 01:00:20 2004 GMT
Not After : Nov 28 01:00:20 2005 GMT
Subject: O=Seccure, OU=Seccure Labs, CN=www.seccure.lab
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:c1:19:c7:38:f4:89:91:27:a2:1b:1d:b6:8d:91:
48:63:0e:3d:0d:2e:f8:65:45:56:db:98:4d:11:21:
01:ac:81:8e:3f:64:4a:8a:3f:21:15:ca:49:6e:64:
5c:5d:a2:ab:5a:48:cb:2a:9f:0c:02:b9:ff:52:f6:
d9:39:6d:a3:4a:94:41:f9:e9:ab:f0:42:fb:68:9a:
4b:53:41:e7:4f:b0:2b:02:d7:92:a2:2b:02:a2:f9:
f1:2d:68:fa:50:01:2f:49:c1:28:2f:a8:c6:6d:6d:
ab:1d:b9:bd:c9:80:63:f1:d6:22:19:de:2d:4a:43:
50:76:79:7e:a5:5a:75:af:19
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Server
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, Netscape Server Gated Crypto,
Microsoft Server Gated Crypto
Netscape Comment:
OpenSSL Certificate for SSL Web Server
Signature Algorithm: sha1WithRSAEncryption
45:30:9d:04:0e:b7:86:9e:61:a1:b0:68:2b:44:93:1c:57:2a:
99:42:bb:16:b1:ab:f5:c0:d2:33:12:c8:d3:1d:2b:bb:6b:9a:
4c:c7:53:bc:e4:88:ef:1e:c3:37:ed:53:2c:15:cf:b8:90:df:
df:4b:34:b8:db:cc:23:77:46:06:72:9d:43:60:a8:a2:ed:0a:
bb:1a:a4:e8:4e:ba:66:93:63:74:87:fd:43:48:b6:93:a2:e3:
3d:da:1b:64:46:35:88:b4:4b:22:e6:3c:84:70:5d:88:dd:64:
c2:51:c2:d6:59:80:87:bc:bd:7f:e3:c1:45:7e:c0:5f:9c:ca:
e1:a1
The examples presented in the subsequent sections of this article are based on the following values, as shown in Table 3. In order to create valid certificates, readers will need to replace these values with the names of their own company or organization.
Attribute's description
Attribute
Sample value
Country code (two letters)
C
C = PL
State or Province
S
S = mazowieckie
Location
L
L = Warsaw
Organization Name
O
O = Seccure
Organization Unit
OU
OU = Seccure Labs
Common Name
CN
CN = www.seccure.lab
Table 3. Sample values for a valid certificate.
The passphrase dilemma
Before creating certificates, it is important to understand the implications of a passphrase for the certificate. Should the web server's private key be encrypted or not? There are many opinions, but it is recommended that one does not protect the web server's private key using passphrase. It is not only inconvenient, but also gives a false sense of security. Why? Consider the points below.
1. One is required to enter the passphrase after every restart of the web server, which can be quite annoying if the system needs to be restarted often (such as due to a kernel update, an electricity failure, configuration change, and so on).
2. If an intruder manages to get the private key on the web server, it means that the web server is compromised and the intruder had had access to the web server's operating system at root level. If this is the case, the intruder could obtain the passphrase by installing keylogger, and either crash or restart the system to force administrator to enter the passphrase. Alternatively, an intruder could dump Apache's memory and find the web server's private key stored as clear text there. While it is little bit difficult, for those skilled in the art of hacking Unix it should not pose a big problem (hint: look at the pcat utility from The Coroner's Toolkit).
Therefore, the only advantage of encrypting web server's private key is that the passphrase will help protect web server's private key against script kiddies, but not against professionals who are able to compromise the server.
Creating the web server certificate
At this point we can create our web server certificate. In general, there are three types of certificates that we can use:
1. A self-signed certificate.
2. A certificate signed by trusted CA (most recommended).
3. A certificate signed by a local CA.
The sections below describe in detail the methods of creating the above certificates. The final result of any method used will be just two files:
server.key - the private key of the web server
server.crt - the PEM encoded certificate that includes our web server's public key
Method 1: Self-signed certificate (for testing purposes only)
This method is recommended only for continuing our testing, or for use in small, closed environments (such as at home or in small Intranets). In order for the web browsers to be able to authenticate the web server, self-signed certificates must be installed in every web browser that needs access the web server. This can be quite inconvenient.
The web server's private/public key pair and the self-signed PEM-encoded certificate now can be created as follows:
openssl req \
-new \
-x509 \
-days 365 \
-sha1 \
-newkey rsa:1024 \
-nodes \
-keyout server.key \
-out server.crt \
-subj '/O=Seccure/OU=Seccure Labs/CN=www.seccure.lab'
The above commands will create a new (-new) certificate (-x509) that will be valid for one year (-days 365) and will be signed using the SHA1 algorithm (-sha1). The RSA private key will be 1024 bits long (-newkey rsa:1024), and will not be protected by a passphrase (-nodes). The certificate and the private/public key pair will be created in the "server.crt" and "server.key" files (-out server.crt -keyout server.key). The "-subj" parameter says that the company's name is "Seccure" (O=Seccure), the department's name is "Seccure Labs", and the web server's fully qualified domain name is "www.seccure.lab".
After creating the above certificate, we need to distribute and install it in every web browser that may connect to the web server. Otherwise, web browsers requiring a connection will not be able to verify the web server's identity. For Windows environments, this is shown below in Figure 1.
Figure 1. Installing a self-signed certificate onto a client machine.
Method 2: Certificate signed by a trusted CA (recommended method)
Creating a certificate request and signing it by a trusted CA (such as Verisign,Thawte, RSA, or others) is the most recommended way to proceed if the SSL web server is to be exposed to the Internet. Using this approach, there is no need to install certificates in each web browser, since most of them already have a number of trusted CA certificates pre-installed out-of-the-box.
Please note that each Certificate Authority has different restrictions for the Distinguish Name's attributes, to accommodate certain key lengths or international characters, and therefore prior to creating certificate requests readers need to make sure that certificate request is compliant with their particular CA's requirements. It is also recommended that one choose a CA whose signing certificate is already installed in most of web browsers (including Thawte, Verisign, and a number of others). Otherwise, the user's web browser may have problems authenticating with the web server.
The process of obtaining a signed certificate from trusted CA consists of the following steps:
1. In the first step, we should create our web server's private/public key pair (server.key), and certificate request (request.pem), as follows:
openssl req \
-new \
-sha1 \
-newkey rsa:1024 \
-nodes \
-keyout server.key \
-out request.pem \
-subj '/O=Seccure/OU=Seccure Labs/CN=www.seccure.lab'
2. Now we must send the certificate request (request.pem) to the CA, and then wait until it is signed and sent back to us in the form of certificate.
3. After receiving certificate back from our trusted CA, we must make sure that it is encoded in the PEM format, and not in TXT or DER format. If the received certificate is not PEM-encoded, then we will need to convert it from whatever format we have received.
The easiest way to check the format of the certificate is to view the certificate with a text editor. Depending on how the certificate look, it can be in one of the following formats (the typical filename extensions has been presented in the brackets):
o PEM, Base64 encoded X.509 format (*.crt, *.pem, *.cer)
-----BEGIN CERTIFICATE-----
MIICdzCCAeCgAwIBAgIBATANBgkqhkiG9w0BAQUFADAsMRAwDgYDVQQKEwdTZWNj
dXJlMRgwFgYDVQQLEw9TZWNjdXJlIFJvb3QgQ0EwHhcNMDQxMTI4MDEwMDIwWhcN
...
ou0Kuxqk6E66ZpNjdIf9Q0i2k6LjPdobZEY1iLRLIuY8hHBdiN1kwlHC1lmAh7y9
f+PBRX7AX5zK4aE=
-----END CERTIFICATE-----
o TXT + PEM format (*.crt, *.cer, *.pem, *.txt)
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: O=Seccure, OU=Seccure Root CA
...
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:c1:19:c7:38:f4:89:91:27:a2:1b:1d:b6:8d:91:
...
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
...
-----BEGIN CERTIFICATE-----
MIICdzCCAeCgAwIBAgIBATANBgkqhkiG9w0BAQUFADAsMRAwDgYDVQQKEwdTZWNj
dXJlMRgwFgYDVQQLEw9TZWNjdXJlIFJvb3QgQ0EwHhcNMDQxMTI4MDEwMDIwWhcN
...
ou0Kuxqk6E66ZpNjdIf9Q0i2k6LjPdobZEY1iLRLIuY8hHBdiN1kwlHC1lmAh7y9
f+PBRX7AX5zK4aE=
-----END CERTIFICATE-----
o If your certificate was received in TXT + PEM format, here is the command to convert it to PEM:
openssl x509 -in signed_cert.pem -out server.crt
o DER, binary encoded X.509 (*.der, *.crt, *.cer)

[ non-text, binary representation ]

o If your certificate was received in DER format, here is the command to convert it to PEM:
openssl x509 -in signed_cert.der -inform DER -out server.crt
4. Verify and test the certificate
Before installing the certificate we should check if the received certificate is indeed valid and can be used for web server authentication purposes:
openssl verify -CAfile /path/to/trusted_ca.crt -purpose sslserver server.crt
Also, it is good to make sure that the certificate corresponds to our previously created web server's private key (the results of both commands below should be identical):
openssl x509 -noout -modulus -in server.crt openssl sha1
openssl rsa -noout -modulus -in server.key openssl sha1
Method 3: Certificate signed by a local CA
This third method of signing a certificate can be used in Intranets as well as all organizations that use, or plan to use, their own Certification Authority. In this case, a local CA certificate must be installed in all web browsers that connect to the secure web server.
To be able to use this method, we need to create our local CA's private/public key, as well as the CA's certificate and repository for the new keys.
Note: The local CA should be created on a separate server that is not connected to the network at all. The operating system should allow access only to authorized people, and the machine itself should be physically secured. The CA's private key is the most precious element of the entire PKI system - if this key is compromised, then all other certificates signed by this CA are considered compromised as well!
We will use the OpenSSL library to setup the environment step by step, as listed below. Of course, if we already have a local CA, we can skip this section and proceed with creating the certificate request for the web server.
1. Prepare the directory structure for the new CA (the $SSLDIR environment variable should be added to applicable startup scripts, such as /etc/profile or /etc/rc.local):
export SSLDIR=$HOME/ca
mkdir $SSLDIR
mkdir $SSLDIR/certs
mkdir $SSLDIR/crl
mkdir $SSLDIR/newcerts
mkdir $SSLDIR/private
mkdir $SSLDIR/requests
touch $SSLDIR/index.txt
echo "01" > $SSLDIR/serial
chmod 700 $SSLDIR
2. Create the main OpenSSL configuration file - $SSLDIR/openssl.cnf, with the following content (optimized for the use with SSL web servers):
# =================================================
# OpenSSL configuration file
# =================================================

RANDFILE = $ENV::SSLDIR/.rnd

[ ca ]
default_ca = CA_default

[ CA_default ]
dir = $ENV::SSLDIR
certs = $dir/certs
new_certs_dir = $dir/newcerts
crl_dir = $dir/crl
database = $dir/index.txt
private_key = $dir/private/ca.key
certificate = $dir/ca.crt
serial = $dir/serial
crl = $dir/crl.pem
RANDFILE = $dir/private/.rand
default_days = 365
default_crl_days = 30
default_md = sha1
preserve = no
policy = policy_anything
name_opt = ca_default
cert_opt = ca_default

[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

[ req ]
default_bits = 1024
default_md = sha1
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
string_mask = nombstr

[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (eg, YOUR name)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64

[ usr_cert ]
basicConstraints = CA:FALSE
# nsCaRevocationUrl = https://url-to-exposed-clr-list/crl.pem

[ ssl_server ]
basicConstraints = CA:FALSE
nsCertType = server
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, nsSGC, msSGC
nsComment = "OpenSSL Certificate for SSL Web Server"

[ ssl_client ]
basicConstraints = CA:FALSE
nsCertType = client
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
nsComment = "OpenSSL Certificate for SSL Client"

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ v3_ca ]
basicConstraints = critical, CA:true, pathlen:0
nsCertType = sslCA
keyUsage = cRLSign, keyCertSign
extendedKeyUsage = serverAuth, clientAuth
nsComment = "OpenSSL CA Certificate"

[ crl_ext ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
nsComment = "OpenSSL generated CRL"
3. Now create the CA's private/public key pair, and the self-signed CA's certificate:
openssl req \
-config $SSLDIR/openssl.cnf \
-new \
-x509 \
-days 3652 \
-sha1 \
-newkey rsa:1024 \
-keyout $SSLDIR/private/ca.key \
-out $SSLDIR/ca.crt \
-subj '/O=Seccure/OU=Seccure Root CA'
4. It should be emphasized that the CA's private key (ca.key) should be protected by a hard to guess passphrase, and it should be valid for a much longer period of time than regular certificates (typically, 10-30 years, or more).
The CA's certificate "ca.crt" should be published on Intranet web pages and installed in every web browser that may possibly need to use it. A sample root CA certificate installed in Internet Explorer is shown below in Figure 2.
Figure 2. Sample root CA certificate installed in Internet Explorer.
From this point we can now use our local CA for signing/revoking certificates. In order to create the web server certificate, we should follow the below steps:
1. Create the web server's private/public key pair (server.key), and the certificate request (request.pem). This instruction needs to be executed on the web server.
openssl req \
-new \
-sha1 \
-newkey rsa:1024 \
-nodes \
-keyout server.key \
-out request.pem \
-subj '/O=Seccure/OU=Seccure Labs/CN=www.seccure.lab'
2. Copy the above certificate request (request.pem) into the $SSLDIR/requests directory on the CA host (using removable media, such as a USB-Drive).
3. Sign the certificate request as follows (to be executed on the CA host only):
openssl ca \
-config $SSLDIR/openssl.cnf \
-policy policy_anything \
-extensions ssl_server \
-out $SSLDIR/requests/signed.pem \
-infiles $SSLDIR/requests/request.pem
4. The result of the above command is a signed certificate (signed.pem) that is placed in the $SSLDIR/newcerts directory, and in the file $SSLDIR/signed.pem. It consists of both a TXT and PEM representation of the certificate. Because Apache expects a pure PEM format, we need to convert it, as follows:
openssl x509 \
-in $SSLDIR/requests/signed.pem \
-out $SSLDIR/requests/server.crt
5. Copy the signed, PEM-encoded certificate (server.crt) back to the web server machine.
At this point web server's certificate is ready to use.
For local Certificate Authorities, if the web server's certificate is compromised it is CA responsibility to revoke the certificate, and to inform users and applications that this certificate is no longer valid.
To revoke a certificate, we need to find the serial number of the certificate we want to revoke in the $SSLDIR/index.txt file. Then, we can revoke the certificate as follows:
openssl ca \
-config $SSLDIR/openssl.cnf \
-revoke $SSLDIR/newcerts/.pem
To create a CRL (Certificate Revocation List) file, we can use the following commands:
openssl ca -config $SSLDIR/openssl.cnf -gencrl -crlexts crl_ext -md sha1 -out $SSLDIR/crl.pem
The above file should be published on the CA's website, and/or distributed to users. When distributing CRLs it is also recommended that one use the Online Certificate Status Protocol (OCSP). More information about OCSP can be found in RFC 2560 .
Note that some browsers (including Firefox) accept only DER-encoded CRLs, so prior to installing crl.pem in such browsers, the file must be converted as follows:
openssl crl \
-in $SSLDIR/crl.pem \
-out $SSLDIR/revoke_certs.crl \
-outform DER
Also note that in order for the web browser to check if the web server's certificate is revoked, the option "Check for server certificate revocation" should be checked in MS Internet Explorer's Advanced Settings. This is shown below in Figures 3 and 4.
Figure 3. Configuring Internet Explorer to check for certificate revocation. Figure 4. Internet Explorer's response to a revoked certificate.
Installing the certificate
At this point we can proceed with installing the web server's private key (server.key) and certificate (server.crt) into the Apache environment:
install -m 600 -o root -g sys server.key /usr/local/apache2/conf/ssl.key/
install -m 644 -o root -g sys server.crt /usr/local/apache2/conf/ssl.crt/
We should also make sure that the directives in Apache's configuration file are pointing to the above files (in httpd.conf):
SSLCertificateFile /usr/local/apache2/conf/ssl.crt/server.crt
SSLCertificateKeyFile /usr/local/apache2/conf/ssl.key/server.key
The final step is to restart Apache for the changes to take an effect:
/usr/local/apache2/bin/apachectl stop
/usr/local/apache2/bin/apachectl startssl
At this point we can check to see if the SSL website is accessible from the web browsers, and if the web browsers can successfully authenticate with the web server. This time, there should be no warning messages displayed, as shown below in Figure 5.
Figure 5. Secure connection with a valid certificate.
Concluding part two
It has been shown how to configure mod_ssl, and how to create and use a web server's X.509v3 certificates. Next, in the third and final part of this article series, we will discuss client authentication via certificates, as well as common mistakes and known attacks that can threaten the security of SSL communication.

About the author
Artur Maj works as a Principal Software Engineer for Oracle Corporation, in the EMEA Mobile, Wireless & Voice Center of Expertise. He is experienced in designing computer systems, performing security audits as well as providing security training. He is also author of many articles and publications devoted to securing computer systems and software against intruders.

Apache 2 with SSLTLS Step-by-Step Part 1

For more than 10 years the SSL protocol has been widely used for the purpose of securing web transactions over the Internet. One can only guess how many millions or billions of dollars in transactions are processed per a day using SSL. Unfortunately, the simple fact we use SSL does not necessarily mean that the information sent over this protocol is secure. The use of weak encryption, the impossibility of verifying web servers' certificates, security vulnerabilities in web servers or the SSL libraries, as well as other attacks, may each let intruders access sensitive information -- regardless of the fact that it is being sent through the SSL.
This article begins a series of three articles dedicated to configuring Apache 2.0 with SSL/TLS support in order to ensure maximum security and optimal performance of the SSL communication. This article, part one, introduces key aspects of SSL/TLS and then shows how to install and configure Apache 2.0 with support for these protocols. The second part discusses the configuration of mod_ssl, and then addresses issues with web server authentication. The second article also shows how to create web server's SSL certificate. The third and final article in this series discusses client authentication and some typical configuration mistakes made by administrators that may decrease the security level of any SSL communication.
Introduction to SSL
Secure Sockets Layer (SSL) is the most widely known protocol that offers privacy and good reliability for client-server communication over the Internet. SSL itself is conceptually quite simple: it negotiates the cryptography algorithms and keys between two sides of a communication, and establishes an encrypted tunnel through which other protocols (like HTTP) can be transported. Optionally, SSL can also authenticate both sides of communication through the use of certificates.
SSL is a layered protocol and consists of four sub-protocols:
SSL Handshake Protocol
SSL Change Cipher Spec Protocol
SSL Alert Protocol
SSL Record Layer
The position of the above protocols according to the TCP/IP model has been illustrated on the following diagram in Figure 1.
Figure 1. SSL sub-protocols in the TCP/IP model
As the above diagrams shows, SSL is found in the application layer of the TCP/IP model. By dint of this feature, SSL can be implemented on almost every operating system that supports TCP/IP, without the need to modify the system kernel or the TCP/IP stack. This gives SSL a very strong advantage over other protocols like IPSec (IP Security Protocol), which requires kernel support and a modified TCP/IP stack. SSL can also be easily passed through firewalls and proxies, as well as through NAT (Network Address Translation) without issues.
How does SSL work? The diagram below, Figure 2, shows the simplified, step-by-step process of establishing each new SSL connection between the client (usually a web browser) and the server (usually an SSL web server).
Figure 2. How SSL established connections, step-by-step.
As you can see from Figure 2, the process of establishing each new SSL connection starts with exchanging encryption parameters and then optionally authenticating the servers (using the SSL Handshake Protocol). If the handshake is successful and both sides agree on a common cipher suite and encryption keys, the application data (usually HTTP, but it can be another protocol) can be sent through encrypted tunnel (using the SSL Record Layer).
In reality, the above process is in fact a little bit more complicated. To avoid unnecessary handshakes, some of the encryption parameters are being cached. Alert messages may be sent. Ciphers suites can be changed as well. However, regardless of the SSL specification details, the most common way this process actually works is very similar to the above.
SSL, PCT, TLS and WTLS (but not SSH)
Although SSL is the most known and the most popular, it is not the only protocol that has been used for the purpose of securing web transactions. It is important to know that since invention of SSL v1.0 (which has never been released, by the way) there have been at least five protocols that have played a more-or-less important role in securing access to World Wide Web, as we see below:
SSL v2.0Released by Netscape Communications in 1994. The main goal of this protocol was to provide security for transactions over the World Wide Web. Unfortunately, very quickly a number of security weaknesses were found in this initial version of the SSL protocol, thus making it less reliable for commercial use:
weak MAC construction
possibility of forcing parties to use weaker encryption
no protection for handshakes
possibility of an attacker performing truncation attacks
PCT v1.0Developed in 1995 by Microsoft. Privacy Communication Technology (PCT) v1.0 addressed some weaknesses of SSL v2.0, and was aimed to replace SSL. However, this protocol has never gained as much popularity as SSL v3.0.
SSL v3.0Released in 1996 by Netscape Communications. SSL v3.0 solved most of the SSL v2.0 problems, and incorporated many of the features of PCT. Pretty quickly become the most popular protocol for securing communication over WWW.
TLS v1.0 (also known as SSL v3.1)Published by IETF in 1999 (RFC 2246). This protocol is based on SSL v3.0 and PCT and harmonizes both Netscape's and Microsoft's approaches. It is important to note that although TLS is based on SSL, it is not a 100% backward compatible with its predecessor. IETF did some security improvements, such as using HMAC instead of MAC, using a different calculation of the master secret and key material, adding additional alert codes, no support for Fortezza cipher suites, and so on. The end result of these improvements is that these protocols don't fully interoperate. Fortunately enough, TLS has also got a mode to fall back to SSL v3.0.
WTLS"Mobile and wireless" version of the TLS protocol that uses the UDP protocol as a carrier. It is designed and optimized for the lower bandwidth and smaller processing capabilities of WAP-enabled mobile devices. WTLS was introduced with the WAP 1.1 protocol, and was released by the WAP Forum. However, after the introduction of the WAP 2.0 protocol, WTLS has been replaced by a profiled version of the TLS protocol, which is much more secure -- mainly because there is no need for decryption and re-encryption of the traffic at the WAP gateway.
Why has the SSH (Secure Shell) protocol not been used for the purpose of providing secure access to World Wide Web? There are few reasons why not. First of all, from the very beginning TLS and SSL were designed for securing web (HTTP) sessions, whereas SSH was indented to replace Telnet and FTP. SSL does nothing more than handshake and establishing encryption tunnel, and at the same time SSH offers console login, secure file transfer, and support for multiple authentication schemes (including passwords, public keys, Kerberos, and more). On the other hand, SSL/TLS is based on X.509v3 certificates and PKI, which makes the distribution and management of authentication credentials much easier to perform. Hence, these and other reasons make SSL/TLS more suitable for securing WWW access and similar forms of communication, including SMTP, LDAP and others -- whereas SSH is more convenient for remote system management.
To summarize, although several "secure" protocols do indeed exist, only two of them should be used for the purpose of securing web transactions (at least at the moment): TLS v1.0 and SSL v3.0. Both of them are further referred in this article series as simply SSL/TLS. Because of known weaknesses of SSL v2.0, and the famous "WAP gap" in case of WTLS, the use of these other protocols should be avoided or at least minimized.
Software requirements
This next part of the article shows how to configure Apache 2.0 with SSL/TLS support, using the mod_ssl module. Therefore, before going further, readers are encouraged to download the latest version of Apache's 2.0 source code from Apache's web site. Most of the examples should also work for Apache 1.3.x - in that case, however, mod_ssl need to be downloaded separately from Apache's source code, from the mod_ssl website.
The practical examples presented in the article should work on most Linux, Linux-like and BSD-based operating systems. The only requirement for the operating system is to have both GCC and the OpenSSL library installed.
As a default web browser, MS Internet Explorer has been chosen for our testing, mainly because of ubiquitous popularity of that browser. However, any modern web browser can be used, including FireFox, Mozilla, Netscape, Safari, Opera and others).
Installing Apache with SSL/TLS support
The first step in order to install Apache with SSL/TLS support is to configure and install the Apache 2 web server, and create a user and group named "apache". A secure way of installing Apache's 2.0 has already been published on SecurityFocus in the article Securing Apache 2.0: Step-by-Step. The only difference to that process is to enable mod_ssl and mod_setenvif, which is required to provide compatibility with some versions of MS Internet Explorer, as follows (changes shown in bold):
./configure \
--prefix=/usr/local/apache2 \
--with-mpm=prefork \
--enable-ssl \
--disable-charset-lite \
--disable-include \
--disable-env \
--enable-setenvif \
--disable-status \
--disable-autoindex \
--disable-asis \
--disable-cgi \
--disable-negotiation \
--disable-imap \
--disable-actions \
--disable-userdir \
--disable-alias \
--disable-so
After configuring, we can install Apache into the destination directory:
make
su
umask 022
make install
chown -R root:sys /usr/local/apache2
Configuring SSL/TLS
Before running Apache for a first time, we need also to provide an initial configuration and prepare some sample web content. As a minimum, we need to go through the following steps (as root):
1. Create some sample web content, which will be served up via TLS/SSL:
umask 022
mkdir /www
echo " \
Test works." > /www/index.html
chown -R root:sys /www
2. Replace the default Apache configuration file (normally found in /usr/local/apache2/conf/httpd.conf) with the new one, using the following content (optimized with respect to security and performance).
# =================================================
# Basic settings
# =================================================
User apache
Group apache
ServerAdmin webmaster@www.seccure.lab
ServerName www.seccure.lab
UseCanonicalName Off
ServerSignature Off
HostnameLookups Off
ServerTokens Prod
ServerRoot "/usr/local/apache2"
DocumentRoot "/www"
PidFile /usr/local/apache2/logs/httpd.pid
ScoreBoardFile /usr/local/apache2/logs/httpd.scoreboard

DirectoryIndex index.html


# =================================================
# HTTP and performance settings
# =================================================
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 30

MinSpareServers 5
MaxSpareServers 10
StartServers 5
MaxClients 150
MaxRequestsPerChild 0


# =================================================
# Access control
# =================================================

Options None
AllowOverride None
Order deny,allow
Deny from all


Order allow,deny
Allow from all


# =================================================
# MIME encoding
# =================================================

TypesConfig /usr/local/apache2/conf/mime.types

DefaultType text/plain

AddEncoding x-compress .Z
AddEncoding x-gzip .gz .tgz
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType application/x-tar .tgz
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl


# =================================================
# Logs
# =================================================
LogLevel warn
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
ErrorLog /usr/local/apache2/logs/error_log
CustomLog /usr/local/apache2/logs/access_log combined
CustomLog logs/ssl_request_log \
"%t %h %{HTTPS}x %{SSL_PROTOCOL}x %{SSL_CIPHER}x \
%{SSL_CIPHER_USEKEYSIZE}x %{SSL_CLIENT_VERIFY}x \"%r\" %b"

# =================================================
# SSL/TLS settings
# =================================================
Listen 0.0.0.0:443

SSLEngine on
SSLOptions +StrictRequire


SSLRequireSSL


SSLProtocol -all +TLSv1 +SSLv3
SSLCipherSuite HIGH:MEDIUM:!aNULL:+SHA1:+MD5:+HIGH:+MEDIUM

SSLMutex file:/usr/local/apache2/logs/ssl_mutex

SSLRandomSeed startup file:/dev/urandom 1024
SSLRandomSeed connect file:/dev/urandom 1024

SSLSessionCache shm:/usr/local/apache2/logs/ssl_cache_shm
SSLSessionCacheTimeout 600

SSLPassPhraseDialog builtin
SSLCertificateFile /usr/local/apache2/conf/ssl.crt/server.crt
SSLCertificateKeyFile /usr/local/apache2/conf/ssl.key/server.key

SSLVerifyClient none
SSLProxyEngine off


AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl


SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
3. Note: Readers should change some of the values in the above configuration file such as the name of the web server, the administrator's e-mail address, etc.
4. Prepare the directory structure for web server's private keys, certificates and certification revocation lists (CRLs):
umask 022
mkdir /usr/local/apache2/conf/ssl.key
mkdir /usr/local/apache2/conf/ssl.crt
mkdir /usr/local/apache2/conf/ssl.crl
5. Create a self-signed server certificate (it should be used only for test purposes -- your real certificate should come from a valid CA such as Verisign):
openssl req \
-new \
-x509 \
-days 30 \
-keyout /usr/local/apache2/conf/ssl.key/server.key \
-out /usr/local/apache2/conf/ssl.crt/server.crt \
-subj '/CN=Test-Only Certificate'
Testing the installation
At this point we can start Apache with SSL/TLS support, as follows:
/usr/local/apache2/bin/apachectl startssl
Apache/2.0.52 mod_ssl/2.0.52 (Pass Phrase Dialog)
Some of your private key files are encrypted for security reasons.
In order to read them you have to provide us with the pass phrases.

Server 127.0.0.1:443 (RSA)
Enter pass phrase:*************

Ok: Pass Phrase Dialog successful.
After the server starts, we can try to connect to it by pointing the web browser to the URL of the form: https://name.of.the.web.server (in our case, https://www.seccure.lab)
In few moments, we should see a warning message saying that there is problem with verifying the authentication of the web server we want to access. Below in Figure 3 we will see an example from MS Internet Explorer 6.0.
Figure 3. Anticipated IE 6 certificate warning.
The occurrence of the above warning is perfectly correct. We should receive this message because of two reasons:
The web browser does not know the Certificate Authority which issued the web server's certificate (and cannot know, because we are using self-signed certificate)
The CN (Common Name) attribute of the certificate does not match the name of the website - at the moment it is "Test-Only Certificate", and it should be the fully qualified domain name of the web server (e.g. www.seccure.lab)
After proceeding with Internet Explorer, we should see the following web content as shown below in Figure 4.
Figure 4. Sample working SSL web page.
As one may notice, there is a yellow lock at the bottom of the web browsers, which means that the SSL connection has been successfully established. The value "128-bit" says that the symmetric key that that is being used to encrypt the communication has the length of 128 bits, which is strong enough (at least for the moment) to protect the traffic from unauthorized access.
If we double click the lock icon, we will see the properties of website's certificate, as shown below in Figure 5.
Figure 5. Details of our self-signed certificate.
Troubleshooting
If for some reasons we could not access the website, there is a very useful diagnostic tool known as "s_client" that comes with the OpenSSL library. It can be used to troubleshoot TLS/SSL connections. An example of how to use this tool has been shown below:
/usr/bin/openssl s_client -connect localhost:443
CONNECTED(00000003)
depth=0 /CN=Test-Only Certificate
verify error:num=18:self signed certificate
verify return:1
depth=0 /CN=Test-Only Certificate
verify return:1
---
Certificate chain
0 s:/CN=Test-Only Certificate
i:/CN=Test-Only Certificate
---
Server certificate
-----BEGIN CERTIFICATE-----
MIICLzCCAZigAwIBAgIBADANBgkqhkiG9w0BAQQFADAgMR4wHAYDVQQDExVUZXN0
LU9ubHkgQ2VydGlmaWNhdGUwHhcNMDQxMTIyMTg0ODUxWhcNMDQxMjIyMTg0ODUx
WjAgMR4wHAYDVQQDExVUZXN0LU9ubHkgQ2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcN
AQEBBQADgY0AMIGJAoGBAMEttnihJ7JpksdToPi5ZVGcssUbHn/G+4G43OiLhP0i
KvYuqNxBkSqqM1AanR0BFVEtVCSuq8KS9LLRdQLJ/B1UTMOGz1Pb14WGsVJS+38D
LdLEFaCyfkjNKnUgeKMyzsdhZ52pF9febB+d8cLmvXFve28sTIxLCUK7l4rjT3Xl

AgMBAAGjeTB3MB0GA1UdDgQWBBQ50isUEV6uFPZ0L4RbRm41+i1CpTBIBgNVHSME
QTA/gBQ50isUEV6uFPZ0L4RbRm41+i1CpaEkpCIwIDEeMBwGA1UEAxMVVGVzdC1P
bmx5IENlcnRpZmljYXRlggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQAD
gYEAThyofbK3hg8AJXbAUD6w6+mz6dwsBmcTWLvYtLQUh86B0zWnVxzSLDmwgdUB
NxfJ7yfo0PkqNnjHfvnb5W07GcfGgLx5/U3iUROObYlwKlr6tQzMoysNQ/YtN3pp
52sGsqaOOWpYlAGOaM8j57Nv/eXogQnDRT0txXqoVEbunmM=
-----END CERTIFICATE-----
subject=/CN=Test-Only Certificate
issuer=/CN=Test-Only Certificate
---
No client certificate CA names sent
---
SSL handshake has read 1143 bytes and written 362 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 1024 bit
SSL-Session:
Protocol : SSLv3
Cipher : DHE-RSA-AES256-SHA
Session-ID: 56EA68A5750511917CC42A1B134A8F218C27C9C0241C35C53977A2A8BBB9986A
Session-ID-ctx:
Master-Key: 303B60D625B020280F5F346AB00F8A61A7C4BEA707DFA0ED8D2F52371F8C4F087FB6EFFC02CE3B48F912D2C8929DB5BE
Key-Arg : None
Start Time: 1101164382
Timeout : 300 (sec)
Verify return code: 18 (self signed certificate)
---
GET / HTTP/1.0

HTTP/1.1 200 OK
Date: Mon, 22 Nov 2004 22:59:56 GMT
Server: Apache
Last-Modified: Mon, 22 Nov 2004 17:24:56 GMT
ETag: "5c911-46-229c0a00"
Accept-Ranges: bytes
Content-Length: 70
Connection: close
Content-Type: text/html

Test works.
closed
The s_client tool has many useful options, such as switching on/off a particular protocol (-ssl2, -ssl3, -tls1), choosing a certain cipher suite (-cipher), enabling debug mode (-debug), watching SSL/TLS states and messages (-state, -msg), and some other options which can help us find the source of the problems.
If s_client does not lead us to the source of problem, we should change LogLevel value (in httpd.conf) to "debug", then restart Apache and check its log files (/usr/local/apache2/logs/) for more information.
We can also try to use Ethereal or ssldump. Thanks to these tools, we can passively watch the SSL Handshake messages, and try to find the reason for the failure. A screenshot of doing this using Ethereal is shown below in Figure 6.
Figure 6. Ethereal watching SSL Handshake methods.
Concluding part one
With our secure Apache 2 server up and running with SSL and a sample certificate, this concludes part one of the article series. Next in part two, the reader will see the recommended security and performance settings for mod_ssl, as well as the process for creating a valid web server certificate.
About the author
Artur Maj works as a Principal Software Engineer for Oracle Corporation, in the EMEA Mobile, Wireless & Voice Center of Expertise. He is experienced in designing computer systems, performing security audits as well as providing security training. He is also author of many articles and publications devoted to securing computer systems and software against intruders.

January 20, 2008

Securing Apache Step-by-Step

Securing Apache: Step-by-Step
Artur Maj

This article shows in a step-by-step fashion, how to install and configure the Apache 1.3.x Web server in order to mitigate or avoid successful break-in when new vulnerabilities in this software are found.

Functionality

Before we start securing Apache, we must specify what functionality we expect from the server. Variety of Apache's use makes it difficult to write a universal procedure to secure the server in every case. That's why in this article we'll base on the following functionality:

  • The Web server will be accessible from the Internet; and,
  • Only static HTML pages will be served
  • the server will support name-based virtual hosting mechanism
  • specified Web pages can be accessible only from selected IP addresses or users (basic authentication)
  • the server will log all the Web requests (including information about Web browsers)

It is worth emphasizing that the above model doesn't support PHP, JSP, CGI or any other technologies that make it possible to interact with Web services. The use of such technologies may pose a large security threat, so that even a small, inconspicuous script can radically decrease the server's security level. Why? Primarily, ASP/CGI applications may contain security vulnerabilities (e.g. SQL injection, cross-site-scripting). Secondarily, the technology itself can be dangerous (vulnerabilities in PHP, Perl modules etc.). That's why I strongly recommend using such technologies only when an interaction with a Web site is absolutely necessary.

Security Assumptions

One of the most important elements of every computer project is the specification of security assumptions. This must be fulfilled before the project is implemented. The security assumptions for our Web server are as follows:

  • The operating system must be hardened as much as possible, both against local and remote attacks;
  • The server must not offer any network services except HTTP: (80/TCP);
  • Remote access to the server must be controlled by a firewall, which should block all outbound connections, and allow inbound connections only to the 80/TCP port of the Web server;
  • The Apache Web server must be the only service available on the system;
  • Only absolutely necessary Apache modules should be enabled;
  • Any diagnostic Web pages and automatic directory indexing service must be turned off;
  • The server should disclose the least amount of information about itself (security by obscurity);
  • The Apache server must run under a unique UID/GID, not used by any other system process;
  • Apache's processes must have limited access to the file systems (chrooting); and,
  • No shell programs can be present in the Apache's chrooted environment (/bin/sh, /bin/csh etc.).

Installing the Operating System

Before installing Apache we must choose an operating system, upon which the server will run. We've got a broad choice here, because Apache can be compiled and installed on almost every operating system. The rest of the article instructs how to secure the Apache Web server on FreeBSD (4.7), however the described methods are possible to apply in case of most UNIX/Linux systems. The only operating system I do not recommend using is MS Windows - mainly because of the limited capabilities of securing the Apache.

The first step in securing the Web server is hardening the operating system. A discussion of hardening the operating system is beyond the scope of this article. However, there are a lot of documents on the Net describing how to perform that. Readers are encouraged to conduct their own issue on this topic.

After the system is installed and hardened, we have to add a new group and regular user called "apache" like this (an example from FreeBSD):

pw groupadd apache

pw useradd apache -c "Apache Server" -d /dev/null -g apache -s /sbin/nologin

By default, Apache processes run with privileges of user nobody (except the main process, which runs with root privileges) and GID of group nogroup. This might pose a significant security threat. In case of successful break-in, the intruder can obtain access to all other processes that run under the same UID/GID. Hence, the optimum solution is to run Apache under the UID/GID of a unique regular user/group, dedicated to that software.

Preparing the Software

The next step is to download the latest version of the Apache Web server. Some of Apache's options can be enabled only during compilation time, thus it is important to download the source code instead of the binary version.

After downloading the software, we must unpack it. Then we must decide which modules should remain enabled. A short description of all modules available in the latest version of Apache 1.3.x (1.3.27) can be found at http://httpd.apache.org/docs/mod/.

Apache's Modules

The choice of modules is one of the most important steps of securing Apache. We should go by the rule: the less the better. To fulfill the functionality and security assumptions, the following modules must remain enabled:

Module's name

Description

httpd_core

The core Apache features, required in every Apache installation.

mod_access

Provides access control based on client hostname, IP address, or other characteristics of the client request. Because this module is needed to use "order", "allow" and "deny" directives, it should remain enabled.

mod_auth

Required in order to implement user authentication using text files (HTTP Basic Authentication), which was specified in functionality assumptions.

mod_dir

Required to search and serve directory index files: "index.html", "default.htm", etc.

mod_log_config

Required to implement logging of the requests made to the server.

mod_mime

Required to set the character set, content- encoding, handler, content-language, and MIME types of documents.

All other Apache's modules must be disabled. We can safely turn them off, mainly because we do not need them. By disabling unneeded modules, we can avoid potential break-ins when new security vulnerabilities are found in one of them.

It is also worth to note that two of Apache's modules can be more dangerous than others: mod_autoindex and mod_info. The first module provides for automatic directory indexing, and is enabled by default. It is very easy to use this module in order to check if Apache runs on a server (e.g. http://server_name/icons/) and to get the content of the Web server's directories, when no index files are found in them. The second module, mod_info, should never be accessible from the Internet, mainly because it reveals the Apache server's configuration.

The next question is how to compile modules. The static method seems to be a better choice. If new vulnerabilities in Apache are found, we will probably recompile not just the vulnerable modules, but the whole software. By choosing the static method, we eliminate the need of one more module - mod_so.

Compiling the software

First of all - if exist - any security patches must be applied. Then, the server should be compiled and installed as follows:

./configure --prefix=/usr/local/apache --disable-module=all --server-

uid=apache --server-gid=apache --enable-module=access --enable-

module=log_config --enable-module=dir --enable-module=mime --enable-module=auth

make

su

umask 022

make install

chown -R root:sys /usr/local/apache

Chrooting the server

The next step is to limit Apache processes' access to the filesystems. We can achieve that by chrooting it's main daemon (httpd). Generally, the chrooting technique means creating a new root directory structure, moving all daemon files to it, and running the proper daemon in that new environment. Thanks to that, the daemon (and all child processes) will have access only to the new directory structure.

We'll start this process by creating a new root directory structure under the /chroot/httpd directory:

mkdir -p /chroot/httpd/dev

mkdir -p /chroot/httpd/etc

mkdir -p /chroot/httpd/var/run

mkdir -p /chroot/httpd/usr/lib

mkdir -p /chroot/httpd/usr/libexec

mkdir -p /chroot/httpd/usr/local/apache/bin

mkdir -p /chroot/httpd/usr/local/apache/logs

mkdir -p /chroot/httpd/usr/local/apache/conf

mkdir -p /chroot/httpd/www

The owner of all above directories must be root, and the access rights should be set to the 0755. Next, we'll create the special device file: /dev/null:

ls -al /dev/null

crw-rw-rw- 1 root wheel 2, 2 Mar 14 12:53 /dev/null

mknod /chroot/httpd/dev/null c 2 2

chown root:sys /chroot/httpd/dev/null

chmod 666 /chroot/httpd/dev/null

A different method must be used to create a /chroot/httpd/dev/log device, which is also needed for the server to work properly. In case of the FreeBSD system, the following line should be added to the /etc/rc.conf:

syslogd_flags="-l /chroot/httpd/dev/log"

We must restart the system or the syslogd daemon itself for the changes to take effect. In order to create a /chroot/httpd/dev/log device on other operating systems, we must take a look at the proper manuals (man syslogd).

The next step is to copy the main httpd program into the new directory tree with all necessary binaries and libraries. In order to do that, we must prepare the list of all required files. We can make such list by using the following commands (their presence depends on particular operating system):

Command

Availability

Descript ion

ldd

All

Lists dynamiic dependencies of executable files or shared libraries

ktrace/ktruss/kdump

*BSD

Enables kernal process tracing, Displays kernal trace data

sotruss

Solaris

Traces shared library procedure calls

strace/ltrace

Linux

Traces system calls and signals

strings

All

Finds the printable strings in binary files

trace

AIX

Records selected system events

trace (freeware)

HP-UX <10.20

Print system call and kernal traces of processes

truss

FreeBSD, Solaris, AIX 5L, SCO Unixware

Traces system calls and signals

tusc (freeware)

HP-UX>11

Traces the system calls a process invokes in HP-UX 11

Examples of using ldd, strings and truss commands are shown below:

localhost# ldd /usr/local/apache/bin/httpd

/usr/local/apache/bin/httpd:

libcrypt.so.2 => /usr/lib/libcrypt.so.2 (0x280bd000)

libc.so.4 => /usr/lib/libc.so.4 (0x280d6000)

localhost# strings /usr/local/apache/bin/httpd | grep lib

/usr/libexec/ld-elf.so.1

libcrypt.so.2

libc.so.4

localhost# truss /usr/local/apache/bin/httpd | grep open

(...)

open("/var/run/ld-elf.so.hints",0,00) = 3 (0x3)

open("/usr/lib/libcrypt.so.2",0,027757775370) = 3 (0x3)

open("/usr/lib/libc.so.4",0,027757775370) = 3 (0x3)

open("/etc/spwd.db",0,00) = 3 (0x3)

open("/etc/group",0,0666) = 3 (0x3)

open("/usr/local/apache/conf/httpd.conf",0,0666) = 3 (0x3)

(...)

The above commands should be applied not only to the httpd program, but also to all of the libraries and binaries required (libraries often require other libraries). In case of FreeBSD system, the following files have to be copied to the new root directory structure:

cp /usr/local/apache/bin/httpd /chroot/httpd/usr/local/apache/bin/

cp /var/run/ld-elf.so.hints /chroot/httpd/var/run/

cp /usr/lib/libcrypt.so.2 /chroot/httpd/usr/lib/

cp /usr/lib/libc.so.4 /chroot/httpd/usr/lib/

cp /usr/libexec/ld-elf.so.1 /chroot/httpd/usr/libexec/

By using the truss command we can also discover that the following configuration files must be present in the chrooted environment as well:

cp /etc/hosts /chroot/httpd/etc/

cp /etc/host.conf /chroot/httpd/etc/

cp /etc/resolv.conf /chroot/httpd/etc/

cp /etc/group /chroot/httpd/etc/

cp /etc/master.passwd /chroot/httpd/etc/passwords

cp /usr/local/apache/conf/mime.types /chroot/httpd/usr/local/apache/conf/

Note, that from /chroot/httpd/etc/passwords we have to remove all the lines except "nobody" and "apache". In a similar way, we must remove all the lines except "apache" and "nogroup" from /chroot/httpd/etc/group. Next, we have to build the password database as follows:

cd /chroot/httpd/etc

pwd_mkdb -d /chroot/httpd/etc passwords

rm -rf /chroot/httpd/etc/master.passwd

The next step is to test if the httpd server runs correctly in the new chrooted environment. In order to perform that, we have to copy the default Apache configuration file and sample index.html:

cp /usr/local/apache/conf/httpd.conf /chroot/httpd/usr/local/apache/co

nf/

cp /usr/local/apache/htdocs/index.html.en /chroot/httpd/www/index.html

After copying the aforementioned files, we must change the DocumentRoot directive as presented below (in /chroot/httpd/usr/local/apache/conf/httpd.conf):

DocumentRoot "/www"

Next, we can try to run the server:

chroot /chroot/httpd /usr/local/apache/bin/httpd

If any problems occur, I recommend analyzing Apache's log files precisely (/chroot/httpd/usr/local/apache/logs). Alternatively, the following command can be used:

truss chroot /chroot/httpd /usr/local/apache/bin/httpd

The truss program should show the cause of the problems. After eliminating any eventual faults, we can configure the Apache server.

Configuring Apache

The first step is to remove the /chroot/httpd/usr/local/apache/conf/httpd.conf file and create a new one in its place, with content similar to the following:

# =================================================

# Basic settings

# =================================================

ServerType standalone

ServerRoot "/usr/local/apache"

PidFile /usr/local/apache/logs/httpd.pid

ScoreBoardFile /usr/local/apache/logs/httpd.scoreboard

ResourceConfig /dev/null

AccessConfig /dev/null

# =================================================

# Performance settings

# =================================================

Timeout 300

KeepAlive On

MaxKeepAliveRequests 100

KeepAliveTimeout 15

MinSpareServers 5

MaxSpareServers 10

StartServers 5

MaxClients 150

MaxRequestsPerChild 0

# =================================================

# Apache's modules

# =================================================

ClearModuleList

AddModule mod_log_config.c

AddModule mod_mime.c

AddModule mod_dir.c

AddModule mod_access.c

AddModule mod_auth.c

# =================================================

# General settings

# =================================================

Port 80

User apache

Group apache

ServerAdmin Webmaster@www.ebank.lab

UseCanonicalName Off

ServerSignature Off

HostnameLookups Off

ServerTokens Prod

DirectoryIndex index.html

DocumentRoot "/www/vhosts"

# =================================================

# Access control

# =================================================

Options None

AllowOverride None

Order deny,allow

Deny from all

Order allow,deny

Allow from all

Order allow,deny

Allow from all

# =================================================

# MIME encoding

# =================================================

TypesConfig /usr/local/apache/conf/mime.types

DefaultType text/plain

AddEncoding x-compress Z

AddEncoding x-gzip gz tgz

AddType application/x-tar .tgz

# =================================================

# Logs

# =================================================

LogLevel warn

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

LogFormat "%h %l %u %t \"%r\" %>s %b" common

LogFormat "%{Referer}i -> %U" referer

LogFormat "%{User-agent}i" agent

ErrorLog /usr/local/apache/logs/error_log

CustomLog /usr/local/apache/logs/access_log combined

# =================================================

# Virtual hosts

# =================================================

NameVirtualHost *

DocumentRoot "/www/vhosts/www.ebank.lab"

ServerName "www.ebank.lab"

ServerAlias "www.e-bank.lab"

ErrorLog logs/www.ebank.lab/error_log

CustomLog logs/www.ebank.lab/access_log combined

DocumentRoot "/www/vhosts/www.test.lab"

ServerName "www.test.lab"

ErrorLog logs/www.test.lab/error_log

CustomLog logs/www.test.lab/access_log combined

The above configuration includes only the commands that are necessary to fulfill the functionality and security assumptions. In the configuration presented, there are two virtual hosts supported by the Web server:

- www.ebank.lab (www.e-bank.lab)
- www.test.lab

The content of the above Web sites is physically present in the following directories:

- /chroot/httpd/www/vhosts/www.ebank.lab

- /chroot/httpd/www/vhosts/www.test.lab

Each Web site has its own log files, which are present in the following directories:

- /chroot/httpd/usr/local/apache/logs/www.ebank.lab

- /chroot/httpd/usr/local/apache/logs/www.test.lab

The above directories must be created before running the Apache for the first time - otherwise the Apache will not run correctly. The owner of the above directories should be root:sys, and the rights should be set to 0755.

Compared with the default Apache configuration file, the following changes have been made:

  • the number of enabled modules has been significantly reduced
  • Apache doesn't disclose information about its version number (directives: ServerTokens, ServerSignature)
  • Apache's processes (except the root process) are set to be executed with unique regular user's/group's privileges (directives: User, Group)
  • Apache will allow access only to the directories, subdirectories and files, which are explicitly specified in the configuration file (directives: Directory, Allow); all other requests will be denied by default
  • Apache will log more information about HTTP requests

Final steps

At the end we should create a start-up script "apache.sh", the content of which will be similar to the following:

#!/bin/sh

CHROOT=/chroot/httpd/

HTTPD=/usr/local/apache/bin/httpd

PIDFILE=/usr/local/apache/logs/httpd.pid

echo -n " apache"

case "$1" in

start)

/usr/sbin/chroot $CHROOT $HTTPD

;;

stop)

kill `cat ${CHROOT}/${PIDFILE}`

;;

*)

echo ""

echo "Usage: `basename $0` {start|stop}" >&2

exit 64

;;

esac

exit 0

The above script should be copied to the proper directory (depends on particular UNIX system), where by default startup scripts are held. In case of FreeBSD it is the /usr/local/etc/rc.d directory.

Summary

The above method allows achieving a higher security level of the Apache server than the one, offered in the default installation.

Thanks to enabling only the absolutely necessary Apache modules, finding a new vulnerability in one of them doesn't have to indicate that our server is vulnerable. Hiding the Apache's version number, turning off the directory indexing service, chrooting and restricted configuration make a successful break-in very difficult. A chrooted environment has also one more important advantage - immunity to the large number of exploits, mainly because of lack of the shell (/bin/sh, /bin/csh etc.). Even if an intruder will success in executing system commands, escaping the chrooted environment could turn out to be quite a problem.

Relevant Links

Apache HTTP Server Project

Sample httpd.conf

Sample apache.sh


About the author

Artur Maj works as a Principal Software Engineer for Oracle Corporation, in the EMEA Mobile, Wireless & Voice Center of Expertise. He is experienced in designing computer systems, performing security audits as well as providing security training. He is also author of many articles and publications devoted to securing computer systems and software against intruders.

View all articles by Artur Maj on SecurityFocus.