Step by Step: Configuring SSL Under Apache

http://www.onlamp.com/pub/a/onlamp/2008/03/04/step-by-step-configuring-ssl-under-apache.html


Step by Step: Configuring SSL Under Apache


by Juliet Kemp 
03/04/2008

Introduction

With a secure web server, clients can connect to your server secure in the knowledge both that it is who it claims to be and that the transaction is well-encrypted so their data is safe. The best way of doing this is with Apache 2, the leading Linux web server software, and Secure Sockets Layer, a secure communication protocol. Transport Layer Security (TLS) is the successor to SSL, but they work in basically the same way. I'll refer from here on just to SSL.

SSL is a protocol for cryptographically securing transactions between a web browser and a web server. In most cases, only the server end is authenticated, which means that the client has a guarantee that the server is who it claims to be, but not vice versa. However, once the connection is established, both ends are secure, as only the client and the server have access to the key material. This makes sense since for many transactions, the server doesn't care who the client is, as long as it stays the same client throughout the transaction. If you do care about client authentication, it is possible to use client SSL certificates (or htaccess, Kerberos, or other similar methods), but that won't be covered in this article.
As a client, obviously you do care that you're sending whatever private data you wish to encrypt to the person (server) you think you're sending it to. Hence the server, not the client, being authenticated. You also care about preventing a third party from accessing your data as you send it. SSL provides both of these types of security.
The SSL process works as follows:
  1. Client connects to web server and gives a list of available ciphers.
  2. Server picks the strongest cipher that both it and the client support, and sends back a certificate with its name and public encryption key, signed by a trusted Certificate Authority (such as Verisign).
  3. The client checks the certificate with the CA. In practice, clients tend to have a collection of CAs locally, so this can be done without having to contact the CA in realtime, and therefore more quickly.
  4. The client sends back a random number encrypted with the server's public key. Only the client knows the number, and only the server can decrypt it (using its private key); this is where the third-party security comes in.
  5. Server and client use this random number to generate key material to use for the rest of the transaction.
We want this to be as transparent as possible on the client side, to make the transaction as easy as possible.
Setting up Apache with SSL is straightforward, but there are several necessary steps. This article covers how to get a certificate signed by a CA, and how to compile and configure Apache with SSL. I'm using Apache2 with mod_sslApacheSSL (an implementation of Apache with SSL capabilities) is also available, but is now quite old; mod_ssl is a better bet.

Creating a Certificate

The first step is certificate creation. You can create your certificate either with or without a passphrase. The major disadvantage of using a passphrase is that it must be typed every time the web server starts up. So it won't start unattended or automatically on boot, for example, after a power cut. Depending on your setup, this may or may not be significant for you.
In theory, the advantage of having a passphrase is that it increases protection. However, in practice the passphrase doesn't actually give that much protection. If someone can read or copy the private key, then they already have root-level access to the system and could obtain the passphrase, for example by using a program like keylogger. A passphrase will protect against script kiddies, but not against a serious hacker. For most people it's probably not worth using one.
For testing purposes, or for small LANs, you can create a self-signed certificate. This can be done by issuing this command:
openssl req -new -x509 -days 365 -sha1 -newkey rsa:1024 \
-nodes -keyout server.key -out server.crt \
-subj '/O=Company/OU=Department/CN=www.example.com'
Let's have a look at the options in detail:
  • -x509 identifies that a certificate is required, rather than just a certificate request (see below).
  • -days 365 sets the certificate to expire in a year. You may want to extend this period. Make a note of the expiry date so that you can renew it when necessary!
  • -sha1 specifies that SHA1 encryption should be used.
  • rsa:1024 sets the key as 1024 bit RSA.
  • -nodes specifies no passphrase.
  • -keyout and -out specify where to store the certificate and key. The key should be root-readable only; the certificate can be world-readable, and must be readable by the user that Apache runs as.
  • -subj flag sets the company name, department name, and the web site address. If you leave these out, you'll be prompted for them. The CN must be the same as the address of your web site, otherwise the certificate won't match and users will receive a warning when connecting. Make sure you don't use a challenge password.
The problem with using a self-signed certificate for a real-life working web server is that any browser connecting to the site will not recognize the certificate authority. This means that the user will be asked to verify the certificate. Obviously, in most cases this is suboptimal. However, it's fine for test purposes, and on small LANs it may not be worth paying for a certificate from an external CA.

For most uses, though, and certainly for dealing with external customers, it will be better to use a certificate that's signed by a trusted Certificate Authority such as Verisign (who have the largest share of the market), or a smaller organization. Most browsers already have a number of trusted CAs preinstalled, which will verify your web server's certificate when the client connects. This minimizes the hassle to the end user, and ensures that they are certain your site is legitimate.
To get a certificate signed by a CA, you first need to create a keypair and a certificate request:
openssl req -new -sha1 -newkey rsa:1024 -nodes \ 
-keyout server.key -out www.example.com.csr \ 
-subj '/O=Company/OU=Department/CN=www.example.com'
This works much as the previous example, but this time, we don't use the -x509 switch. The command will therefore generate a key and certificate request, but not a certificate. If you fill in the CN, etc., when challenged rather than on the command line, you should not fill in an email address or a challenge password.
The server key (server.key, which again should only be readable by root) stays on your web server; the request (www.example.com.csr) goes to the CA. You can call the request file whatever you want, but calling it by your domain name will simplify life for the CA.
The next stage, then, is to send that www.example.com.csr file to the CA, with your payment. They should be able to turn it around fairly quickly, if you have provided all required information with your certificate request. Your chosen CA will explain their procedures on their webpage. You may need to change it into PEM format, but in the case of Verisign, this shouldn't be necessary.
When you get it back and have it in PEM format, rename it to server.crt (this isn't strictly necessary but fits with Apache conventions) and verify it:
    openssl verify -CAfile /path/to/trusted_ca.crt -purpose sslserver server.crt
Next, check that the output of these two commands is the same, i.e., that the certificate corresponds to the private key:
    openssl x509 -noout -modulus -in server.pem | openssl sha1
    openssl rsa -noout -modulus -in server.key | openssl sha1
Now install your key (generated as server.key above) and certificate (server.crt), into /etc/apache2/ssl, or your preferred Apache2 config directory, if that's different. As mentioned above, it's important to make sure that the server.key is readable only by root, while the server certificate should be world-readable, but owned and writeable only by root.

Compiling Apache with SSL

So that's your certificate generated. Next you need to set up your web server to use it.
For the vast majority of people, the best way to install and manage Apache2 and its modules is via your distribution's package management system. The Debian Apache2 web server comes with the SSL module available, but it is not automatically enabled. In order to enable it you must execute: a2enmod ssl and restart the web server.
The generic way to do this is to have the line
    Include /etc/apache2/mod_ssl.conf
in your /etc/apache2/apache2.conf (this file may also be called httpd.conf). You'll need to edit it to give the appropriate location for mod_ssl.conf in your setup. Then restart the web server.
If you wish to compile Apache2 from source, depending on what options you have previously used, you may or may not already have SSL support. Check with the command apache2 -l. If you do need to recompile, run ./configure with all options you previously used, and the addition of --enable-ssl and --enable-setenvif (the latter is needed for compatibility with some Internet Explorer quirks). Then install with make;make install as usual, and check that the ownership and permissions are correct.

Configuring Apache with SSL

Next, you need to configure Apache2. The following instructions assume that you wish to run both a secure server (on port 443) and a regular server (on port 80). First, you need to configure the server to listen on both ports. Either edit /etc/apache2/ports.conf (in Debian; this is included in apache2.conf) or edit /etc/apache2/apache2.confdirectly to include the lines:
Listen 80
Listen 443
Next, edit /etc/apache2/sites-enabled/yoursite to use the SSL settings. Separating the regular and secure server settings out by using VirtualHosts is the easiest option in terms of maintainability. Any configuration outside the VirtualHosts sections (such as setting the ServerAdmin) will apply to both (and any other) VirtualHosts. Add the following section to your config file:

# =================================================
# SSL/TLS settings
# =================================================
NameVirtualHost *:443



    DocumentRoot "/local/www/ssl_html"

    SSLEngine on
    SSLOptions +StrictRequire

    
        SSLRequireSSL
    

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

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

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

    SSLCertificateFile /etc/apache2/ssl/server.crt
    SSLCertificateKeyFile /etc/apache2/ssl/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
A few notes on this configuration:

  • SSLEngine must be enabled so that the server uses SSL.
  • DocumentRoot sets the root directory for this virtual host. This means that you can separate secure content entirely from regular content.
  • SSLRequireSSL requires SSL to be used (on this virtual host): i.e., a user can't connect to this host using a regular HTTP request. This is why we separate out the secure and regular root directory.
  • SSLProtocol disables all protocols other than TLS v1.0 and SSL v3.0. This will be OK for current web browsers.
  • SSLCipherSuite is set to use only HIGH and MEDIUM security cipher suites. SHA1 is considered to be more secure than MD5 so is preferred.
  • SSLCertificateFile and SSLCertificateKeyFile should be set to the locations where you put your certificate and key files.
  • SSLVerifyClient should be set to none if not using client authentication.
To run the regular server on port 80, add the following section to the config file:
NameVirtualHost *:80


    DocumentRoot "/local/www/html"
    # Host-specific directory setup, options, etc
    # Most of these options are likely to be set outside the VirtualHosts
    # sections.
After you've saved the edited configuration file, restart the web server. If you did use a passphrase when generating your certificate, you'll need to enter it when challenged.

Testing

Create a basic index.html page wherever the root directory for your web server is located, if you don't already have content there.
Then point your web browser at https://www.yoursite.com. You should see an SSL connection opened and the page delivered. If you're using a self-signed certificate, your browser will pop up an alert warning you that the server's identity cannot be verified. You can choose to view and accept the certificate. If using an external certificate, it should all happen without intervention.
Make sure as well that you can't access the protected content using http://. If you try, you should get an error message.

Troubleshooting

If it's not working as expected, first check that your server is actually running, using ps -a | grep apache. If that doesn't return anything, try restarting it, and check for error messages on the terminal.
Also check that the permissions on your key and certificate files are set correctly (see above), as well as the permissions on your test HTML file and its parent directory.
Next, check the logs. You should check both the main server logs and also the SSL logs that you set up in your config file above. If you don't get anything useful, try changing the LogLevel value in the Apache2 config file to "debug", restart Apache2, and test again. This should give more logfile data.
If you are running a regular web server on port 80 as well, try fetching a test page via http:// rather than https:// to help identify whether the problem is with the web server or with the SSL connection. Note that in the setup above, the web server's root directory is different for http:// and https://, so you won't (or shouldn't!) be able to access the same content. If your test page in the http:// root directory works fine, though, and your test page in the https:// root directory doesn't, then that can help you to pinpoint the problem.
If the problem is the SSL connection, a useful tool is s_client, which is a diagnostic tool for troubleshooting TLS/SSL connections. The basic usage is: /usr/bin/openssl s_client -connect localhost:443. There are numerous other options as well, for which you can check the documentation. If you get error messages, this should help you in locating the problem.

Conclusion

Congratulations! You should now have a working secure server, with a certificate that will be automatically verified by the majority of modern browsers.
Juliet Kemp has been playing with Linux systems for around 6 years now, after discovering that it was an excellent way to avoid Finals revision. She is currently sysadmin for the Astrophysics group at Imperial College, in London (UK), and is responsible for wrangling a Linux+Solaris network and its users.

留言

熱門文章