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:
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_ssl. ApacheSSL (an implementation of Apache with SSL capabilities) is also available, but is now quite old; mod_ssl is a better bet.
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:
-x509identifies that a certificate is required, rather than just a certificate request (see below).
-days 365sets 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!
-sha1specifies that SHA1 encryption should be used.
rsa:1024sets the key as 1024 bit RSA.
-nodesspecifies no passphrase.
-outspecify 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.
-subjflag 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 (
/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.
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
/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-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.
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.conf directly to include the lines:
Listen 80 Listen 443
/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 <VirtualHost *:443> DocumentRoot "/local/www/ssl_html" SSLEngine on SSLOptions +StrictRequire <Directory /> SSLRequireSSL </Directory> 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 <IfModule mime.c> AddType application/x-x509-ca-cert .crt AddType application/x-pkcs7-crl .crl </IfModule> SetEnvIf User-Agent ".*MSIE.*" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 </VirtualHost>
A few notes on this configuration:
SSLEnginemust be enabled so that the server uses SSL.
DocumentRootsets the root directory for this virtual host. This means that you can separate secure content entirely from regular content.
SSLRequireSSLrequires 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.
SSLProtocoldisables all protocols other than TLS v1.0 and SSL v3.0. This will be OK for current web browsers.
SSLCipherSuiteis set to use only HIGH and MEDIUM security cipher suites. SHA1 is considered to be more secure than MD5 so is preferred.
SSLCertificateKeyFileshould be set to the locations where you put your certificate and key files.
SSLVerifyClientshould 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 <VirtualHost *:80> DocumentRoot "/local/www/html" # Host-specific directory setup, options, etc # Most of these options are likely to be set outside the VirtualHosts # sections. </VirtualHost>
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.
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.
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.
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.
Return to ONLamp.
Copyright © 2009 O'Reilly Media, Inc.