Team LiB
Previous Section Next Section

4.4. Apache and SSL

If you are using Apache from the 2.x branch, the support for SSL is included with the distribution. For Apache 1, it is a separate download of one of two implementations. You can use mod_ssl ( or Apache-SSL ( Neither of these two web sites discusses why you would choose one instead of the other. Historically, mod_ssl was created out of Apache-SSL, but that was a long time ago and the two implementations have little in common (in terms of source code) now. The mod_ssl implementation made it into Apache 2 and is more widely used, so it makes sense to make it our choice here.

Neither of these implementations is a simple Apache module. The Apache 1 programming interface does not provide enough functionality to support SSL, so mod_ssl and Apache-SSL rely on modifying the Apache source code during installation.

4.4.1. Installing mod_ssl

To add SSL to Apache 1, download and unpack the mod_ssl distribution into the same top folder where the existing Apache source code resides. In my case, this is /usr/local/src. I will assume you are using Apache Version 1.3.31 and mod_ssl Version 2.8.19-1.3.31:

$ cd /usr/local/src
$ wget -q
$ tar zxvf mod_ssl-2.8.19-1.3.31.tar.gz
$ cd mod_ssl-2.8.19-1.3.31
$ ./configure --with-apache=../apache_1.3.31

Return to the Apache source directory (cd ../apache_1.3.31) and configure Apache, adding a --enable-module=ssl switch to the configure command. Proceed to compile and install Apache as usual:

$ ./configure --prefix=/usr/local/apache --enable-module=ssl
$ make
# make install

Adding SSL to Apache 2 is easier as you only need to add a --enable-ssl switch to the configure line. Again, recompile and reinstall. I advise you to look at the configuration generated by the installation (in httpd.conf for Apache 1 or ssl.conf for Apache 2) and familiarize yourself with the added configuration options. I will cover these options in the following sections.

4.4.2. Generating Keys

Once SSL is enabled, the server will not start unless a private key and a certificate are properly configured. Private keys are commonly protected with passwords (also known as passphrases) to add additional protection for the keys. But when generating a private key for a web server, you are likely to leave it unprotected because a password-protected private key would require the password to be manually typed every time the web server is started or reconfigured. This sort of protection is not realistic. It is possible to tell Apache to ask an external program for a passphrase (using the SSLPassPhraseDialog directive), and some people use this option to keep the private keys encrypted and avoid manual interventions. This approach is probably slightly more secure but not much. To be used to unlock the private key, the passphrase must be available in cleartext. Someone who is after the private key is likely to be determined enough to continue to look for the passphrase.

The following generates a nonprotected, 1,024-bit server private key using the RSA algorithm (as instructed by the genrsa command) and stores it in server.key:

# cd /usr/local/apache/conf
# mkdir ssl
# cd ssl
# openssl genrsa -out server.key 1024
Generating RSA private key, 1024 bit long modulus
e is 65537 (0x10001)

Only the private key was generated:

# cat server.key

But the public key can be extracted from the private key:

# openssl rsa -in server.key -pubout
writing RSA key
-----END PUBLIC KEY-----

4.4.3. Generating a Certificate Signing Request

The next step is to create a certificate-signing request (CSR). This is a formal request asking a certificate authority to sign a certificate, and it contains the public key of the entity requesting the certificate and information about the entity. The information becomes part of the certificate.

CSR creation is an interactive process, which takes the private server key as input. Read the instructions given by the openssl tool carefully: if you want a field to be empty, you must enter a single dot (.) and not just press Return because doing so would populate the field with the default value.

# openssl req -new -key server.key -out server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [GB]:
State or Province Name (full name) [Berkshire]:.
Locality Name (eg, city) [Newbury]:London
Organization Name (eg, company) [My Company Ltd]:Apache Security
Organizational Unit Name (eg, section) [  ]:.
Common Name (eg, your name or your server's hostname) [  ]:
Email Address [  ]
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password [  ]:
An optional company name [  ]:

After a CSR is generated, you use it to sign your own certificate and/or send it to a public CA and ask him to sign the certificate. Both approaches are described in the sections that follow.

4.4.4. Signing Your Own Certificate

For testing purposes, you should sign your own certificate; it may be days before the CA completes the certificate generation process. You have the files you need: the CSR and the private key. The x509 command with the -req switch creates a self-signed certificate. Other switches on the following command line instruct openssl to create a certificate valid for 365 days using the private key specified in server.key:

# openssl x509 -req -days 365 -in server.csr \
> -signkey server.key -out server.crt
Signature ok
Getting Private key

Use the x509 command to examine the contents of the certificate you have created:

# openssl x509 -text -in server.crt
        Version: 1 (0x0)
        Serial Number: 0 (0x0)
        Signature Algorithm: md5WithRSAEncryption
        Issuer: C=GB, L=London, O=Apache Security,
            Not Before: Jul 26 13:36:34 2004 GMT
            Not After : Jul 26 13:36:34 2005 GMT
        Subject: C=GB, L=London, O=Apache Security,
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                Exponent: 65537 (0x10001)
    Signature Algorithm: md5WithRSAEncryption

4.4.5. Getting a Certificate Signed by a CA

To get a publicly recognized certificate, you will send the generated CSR to a CA. The CA will collect payment, validate your organization's identity, and issue a certificate. Certificates used to be very expensive but, thanks to competing CAs, are now inexpensive enough to allow all but the smallest organizations to use valid public certificates for internal installations.

Most CAs offer free trials so you can practice before making the purchase. Thawte, for example, is offering a script that generates test certificates instantly when fed with CSRs. That script and further information is available at

Forgetting to renew a certificate is one of the most common problems with SSL. Take a minute to create a cron job right on the server to send you an email reminder for this important task.

After receiving the certificate, overwrite the self-signed certificate used for testing and restart Apache. No other changes should be required, but the CA may provide specific installation instructions.

4.4.6. Configuring SSL

A minimal SSL configuration consists of three directives in the Apache configuration file:

# Enable SSL
SSLEngine On
# Path to the server certificate
SSLCertificateFile /usr/local/apache/conf/ssl/server.crt
# Path to the server private key
SSLCertificateKeyFile /usr/local/apache/conf/ssl/server.key

You may wish to make the default configuration slightly more secure by adjusting the allowed protocols. SSLv2 is known to be flawed. (For details, see Unless your installation has to support browsers that do not speak SSLv3 (which is unlikely), there is no reason to allow SSLv2. The following disallows it:

# Allow SSLv3 and TLSv1 but not SSLv2
SSLProtocol All -SSLv2

One other useful configuration option is the following, which disallows the situation where, though the server supports high-grade encryption, the client negotiates a low-grade (e.g., 40-bit) protocol suite, which offers little protection:

# Disallow ciphers that are weak (obsolete or
# known to be flawed in some way). The use of
# an exclamation mark in front of a cipher code
# tells Apache never to use it. EXP refers to 40-bit
# and 56-bit ciphers, NULL ciphers offer no encryption.
# ADH refers to Anonymous Diffie-Hellman key exchange
# which effectively disables server certificate validation,
# and LOW refers to other low strength ciphers.

After the certificate is installed, you can test it by opening the web site in your browser. You should get no warnings for a certificate issued by a well-known CA. You will get at least one warning if you are using a self-signed certificate for testing. In the Appendix A, I introduce SSLDigger, a tool designed to evaluate the strength of a site's SSL protection. Supporting broken SSL clients

Some browsers do not have fully compliant SSL implementations. To make them work with Apache, you need a workaround. The code below is a workaround for problems related to Internet Explorer. The code is in the default SSL configurations, but I have provided it here because you need to be aware of what it does. Whenever the Internet Explorer browser is detected, this configuration fragment disables the HTTP Keep-Alive feature, downgrades the HTTP protocol to 1.0 (from the usual 1.1), and allows the SSL channel to be closed by closing the TCP/IP connection:

# Make SSL work with Internet Explorer
SetEnvIf User-Agent ".*MSIE.*" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0 Securing the server private key

On a server with many user accounts (and not all of them trusted), relaxed permissions on the file with the server private key may result in the key being retrieved by one of the users. The root user should be the only one with permission to read the private key and certificate files:

# cd /usr/local/apache/conf/ssl
# chmod 400 server.crt server.key Ensuring reliable SSL startup

If you are using the apachectl script to start and stop Apache, then you have probably noticed it must be invoked with the startssl command in order to activate SSL. This can lead to problems (and service downtime) when you forget about it and execute the usual apachectl start.

I suggest that you modify this script to make the start command behave in the same manner as startssl, always activating SSL. In the following script fragment, I emphasize where you need to add the -DSSL switch:

case $ARGV in
    ;; Preventing configuration mistakes

If you are running a web site that needs to be available only over SSL, then avoid a chance of making the same content available through a non-SSL channel and create a virtual host that points to an empty folder. Use a RedirectPermanent directive to redirect users to the correct (secure) location:

    DirectoryRoot /var/www/empty
    RedirectPermanent /

If the site contains SSL and non-SSL content, separating the content into two virtual hosts and separate directories decreases the chance of providing sensitive information without SSL. If the content must be put under the same directory tree, consider creating a special folder where the secure content will go. Then tell Apache to allow access to that folder only when SSL is used:

<Directory /var/www/htdocs/secure>
    # SSL must be used to access this location
    # Do not allow SSLRequireSSL to be overriden
    # by some other authorization directive
    SSLOptions +StrictRequire

A site that contains SSL and non-SSL content is more difficult to secure than an SSL-only web site. This is because it is possible for an attacker to eavesdrop on the non-SSL connection to retrieve a cookie that contains the session ID, and then use the stolen session ID to enter the SSL-protected area. The correct approach to handle a case like this is to operate two independent user sessions, one exclusively for the non-SSL part of the site and the other exclusively for the SSL part of the site.

A slightly more user-friendly approach to ensuring content is served over SSL is to use a few mod_rewrite rules to detect access to non-SSL content and redirect the user to the correct location, as demonstrated in Apache Cookbook by Ken Coar and Rich Bowen (O'Reilly) in Recipe 5.15 and online at

RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^/secure(.*) https://%{SERVER_NAME}/secure$1 [R,L]

If neither of these two choices is possible (separating the content into two virtual hosts and separate directories or placing the content in a special folder that can only be accessed using SSL), the burden of controlling SSL access will be on the shoulders of the programmers. You should check (during final site testing) that the secure content available, for example at, cannot be accessed using a nonsecure URL, such as

    Team LiB
    Previous Section Next Section