Professional PHP Programming - Secure transactions using SSL (
Page 7 of 9 )
Using an SSL capable web server, Secure Socket Layer (SSL), is a
great way of improving the security of your web site without having to change
one single line of code. What SSL does is use cryptography to protect the flow
of information between the web server and the browser. Not only does SSL encrypt
all the data flowing over the Internet, it also provides the means for both
parties to authenticate each other. This way, you can buy things on-line without
any third party being able to see your credit card information. These
characteristics make SSL very well suited for use in applications where
sensitive information needs to be exchanged, such as e-commerce and web based
email.
SSL uses an encryption technique called public key
cryptography, where the server end of the connection sends the client a public
key for encrypting information which only the server can decrypt with the
private key it holds. The client uses the public key to encrypt and send the
server its own key, identifying it uniquely to the server and preventing
onlookers at points between the two systems from mimicking either server or
client (generally known as a man-in-the-middle attack).
Secure HTTP
is usually distinguished from regular unencrypted HTTP by being served on a
different port number, 443 instead of 80. Clients told to access a URL with
Secure HTTP automatically connect to port 443 rather than 80, making it easy for
the server to tell the difference and respond appropriately.
There
are several solutions for implementing SSL with Apache including the Apache-SSL
project and the commercial StrongHold and Raven SSL
implementations.
In this section, we're going to look at
implementing SSL with the mod_ssl module and the OpenSSL library. This has a
slight edge over Apache-SSL because it abstracts the actual SSL functionality
into a module, making it possible to load dynamically. It also compiles happily
on both UNIX and Windows platforms.
Using Apache as a specific
example of a webserver, we will just explain how to set it up for use with SSL.
Downloading OpenSSL and ModSSLmod_ssl requires patches to be
made to the original Apache source code. This is somewhat strange, since the
object of mod_ssl was to remove all cryptography code from 'regular' Apache,
allowing it to be distributed freely, and there seems to be no good reason why
the patches aren't incorporated into Apache as standard.
The
Apache source must be patched with the correct version of mod_ssl. For this
reason the mod_ssl package comes with the Apache version number built in, for
example mod_ssl-2.4.4-1.3.9. This translates as 'mod_ssl version 2.4.4 for
Apache 1.3.9'. mod_ssl has its own web site from which current releases can be
downloaded at
http://www.modssl.org/.
mod_ssl tends
to track the current release quite rapidly, but it is possible that a version of
mod_ssl is not yet available for the latest Apache release. In this case we must
either wait for mod_ssl to catch up or use a slightly earlier version of the
Apache source.
OpenSSL also has its own web site, at
http://www.openssl.org/.
In
addition, US sites will need the RSAREF library to comply with patent
restriction. This is no longer available from RSA's own web site but can be
found on a few European FTP servers (RSAREF is patented only in the USA), for
example:
ftp://ftp.replay.com/pub/crypto/crypto/LIBS/rsa/.
Prebuilt
packages are available for both mod_ssl and OpenSSL for some platforms; packages
for Linux systems are available from rpmfind.net and
http://nonus.debian.org.
Be
careful unpacking the archive; it does not put its contents into a single
subdirectory. Instead use something like:
# mkdir /usr/local/src/rsaref-2.0
# cp rsaref20.1996.tar.Z /usr/local/src/rsaref-2.0
# cd /usr/local/src/rsaref-2.0
# gunzip rsaref20.1996.tar.Z
# tar -xf rsaref20.1996.tar
Building and Installing the OpenSSL library After unpacking
OpenSSL, change down into the top directory and run the config script:
# cd /usr/local/src/openssl-0.9.4
# ./config
This should automatically configure the library build for the
target platform. If the config script guesses wrongly (probably because we're
using a platform that it doesn't recognize) we can override it by using the
Configure script instead, as we will see later.
If we want to
install the libraries then we can also set the installation paths. Historically,
the default install location for both the OpenSSL libraries and their support
files is /usr/local/ssl; we can change this by specifying arguments to the
script:
# ./config \
--prefix=/usr/local/apache/libexec/ssl \
--openssldir=/usr/local/apache/ssl
It isn't actually necessary to install OpenSSL completely, as
we can tell mod_ssl where to look for the OpenSSL libraries when we come to
build it. However if we want to use them for other applications or we want to
build them as dynamically linked libraries, it is useful to install them
permanently.
In addition, the following options, none of which have
double minus prefixes, can be used to customize the library:
threads,
no-threads
Explicity enables or disables the use of threaded code in the
library. Threaded code is more efficient, but may cause problems on some
platforms. The default is to let the config script figure it out; this option
might need to be set for more obscure platforms.
no-asm
Does not use
assembly code to build the library. The OpenSSL package comes with fast assembly
language routines for several different processor types and platforms and the
config script will pick one if it finds a suitable match. This option forces the
build process to resort to slower C-based routines instead. Normally the config
script will work this out automatically; use this option to override
it.
386
Relvant to x86 processor architectures only. The default
assembly code provided for these processors requires a 486 or better. Specifying
this option causes OpenSSL to be built with 386 compatible assembly
code.
no-<cipher>
Excludes a particular cipher from the library.
The list of ciphers included (and which can be specified here) is: bf, cast,
des, dh, dsa, hmac, md2, md5, mdc2, rc2, rc4, rc5, rsa, sha. For example:
# ./config no-hmac
rsaref
Causes OpenSSL to be built with the RSAREF
reference implementation rather than its own internal implementation. Inclusion
of the RSAREF library may be required legally. Read the section below before
choosing to enable or ignore this option.
-D, -l, -L, -f, -K
Passes
flags to the compiler or linker stages; for example: -L/usr/local/lib For
example, to configure OpenSSL to use threads, exclude the md2 and rc2 ciphers,
and use RSAREF, we would use:
# ./config \
--prefix=/usr/local/apache/libexec/ssl \
--openssldir=/usr/local/apache/ssl threads no-md2 no-rc2 rsaref
Once the build process is configured, the library can be
built and tested with:
# make (or make all)
# make test
If we are also installing the libraries, we can also use:
# make install
The brave can do all three steps in one go with:
# make all test install > build.log
This creates and installs the OpenSSL libraries as statically
linked libraries with a .a suffix.
Building OpenSSL as Dynamically
Linked LibrariesThe process for building the libraries as dynamically
linked libraries is a little more complicated and depends on the platform. Linux
administrators can use the provided make target linux-shared:
# make linux-shared
The installation step does not understand the shared library
filenames, so to install them we need to install them directly with something
like:
# mv lib* /usr/local/apache/libexec/ssl/
# chmod 664 /usr/local/apache/libexec/ssl/lib*
Since install is also responsible for setting up the
certificate directories and other supporting files, we might want to build the
static libraries first, install them and the supporting files, then build the
shared libraries and install them as a second step:
# make
# make test
# make install
# make linux-shared
# mv lib* /usr/local/apache/libexec/ssl
# chmod 664 /usr/local/apache/libexec/ssl/lib*
Other platforms can try one of the configuration scripts kept
in the shlib subdirectory. Currently scripts exist for IRIX, Solaris and
Windows. Experienced administrators can also try feeding parameters to the
compiler and linker with the -D, -l, -L, -f and -K config script
options.
Specifying the Platform and Compiler
ExplicitlyOpenSSL also comes with an alternative configuration script
Configure that allows us to specify the target platform and compiler explicitly,
rather than have the config script try to work it out itself. Running Configure
on its own will produce a syntax usage line and an alarmingly long list of
possible target platforms and variations:
# ./Configure
Usage: Configure [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [rsaref] [no-threads]
[no-asm] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] os/compiler[:flags]
pick os/compiler from:
BC-16 BC-32 BS2000-OSD CygWin32
FreeBSD FreeBSD-alpha FreeBSD-elf Mingw32
NetBSD-m68 NetBSD-sparc NetBSD-x86 OpenBSD
OpenBSD-alpha OpenBSD-mips OpenBSD-x86 ReliantUNIX
SINIX SINIX-N VC-MSDOS VC-NT
VC-W31-16 VC-W31-32 VC-WIN16 VC-WIN32
aix-cc aix-gcc alpha-cc alpha-gcc
alpha164-cc bsdi-elf-gcc bsdi-gcc cc
cray-t3e cray-t90-cc dgux-R3-gcc dgux-R4-gcc
dgux-R4-x86-gcc dist gcc hpux-brokencc
hpux-brokengcc hpux-cc hpux-gcc hpux10-brokencc
hpux10-brokengcc hpux10-cc hpux10-gcc hpux11-32bit-cc
hpux11-64bit-cc irix-cc irix-gcc irix-mips3-cc
irix-mips3-gcc irix64-mips4-cc irix64-mips4-gcc linux-aout
linux-elf linux-mips linux-ppc linux-sparcv7
linux-sparcv8 linux-sparcv9 ncr-scde nextstep
nextstep3.3 purify sco5-cc sco5-gcc
solaris-sparc-sc3 solaris-sparcv7-cc solaris-sparcv7-gcc solaris-sparcv8-cc
solaris-sparcv8-gcc solaris-sparcv9-cc solaris-sparcv9-gcc solaris-sparcv9-gcc27
solaris-x86-gcc solaris64-sparcv9-cc sunos-gcc ultrix-cc
ultrix-gcc unixware-2.0 unixware-2.0-pentium debug
debug-ben debug-ben-debug debug-ben-strict debug-bodo
The possible options that can be given to Configure are
identical to the config options above with the sole exception of the final
os/compiler option, which is obligatory and picked from the list above. For
example, to build a debug version of OpenSSL on Linux we could use:
# ./Configure [options we supplied to ./config] debug-linux-elf
This should only be necessary if the config script guesses
wrongly or we need to add our own platform to the list if none of the existing
ones work.
Building OpenSSL with the RSAREF toolkitApache
servers that are to run within the US need to build OpenSSL with the RSAREF
library in order to comply with patents held by RSA, at least until they expire.
To do this we unpack the RSAREF source code as outlined above and execute:
# cd /usr/local/src/rsaref-2.0/source
# make -f ../install/unix/makefile
Makefiles exist for UNIX, DOS (Windows) and Macintosh
platforms; we use whichever is the appropriate makefile for the server platform.
To build OpenSSL with the RSAREF library, we copy the RSAREF library to the
OpenSSL root directory and give the rsaref option to the config script:
# cd /usr/local/src/openssl-0.9.4
# cp /usr/local/src/rsaref-2.0/source/rsaref.a librsaref.a
# ./config rsaref [other options]
The RSAREF library is not actively maintained and is now
quite old. Unfortunately, it is a necessary evil for using SSL with Apache in
the US. Administrators compiling onto more obscure or modern platforms,
especially 64 bit architectures, may run into problems. In these cases consult
the mod_ssl installation documentation which covers a few of these
issues.
Building and Installing mod_sslOnce the OpenSSL
libraries - and optionally the RSAREF library - have been built, we can build
mod_ssl. In order to function, mod_ssl needs to patch the Apache source code to
extend the Apache API, so we must use the configuration script supplied with
mod_ssl rather than the one supplied with Apache. Handily, mod_ssl knows how to
drive Apache's configuration script and will pass APACI options to it if we
specify them to mod_ssl's configuration script.
The one-step way to
build Apache and mod_ssl is to give mod_ssl's configuration script something
like the following:
# ./configure --with-apache=/usr/local/src/apache_1.3.9
--with-ssl=/usr/local/src/openssl-0.9.4 --enable-module=ssl
# cd /usr/local/src/apache_1.3.9
# make
# make install
This creates a statically linked Apache with mod_ssl included
into the binary. As well as passing the --enable-module to Apache's
configuration script, this also invisibly passed --enable-rule=EAPI to activate
the patches made to Apache's source code.
Here we've assumed that
we originally unpacked Apache and OpenSSL into directories under /usr/local/src
and have already been into the OpenSSL directory and built the libraries there.
Of course, in reality the source code for the different packages can go anywhere
so long as we tell mod_ssl's configure script where to find
them.
We can supply any APACI options to this configuration script,
and mod_ssl will pass them to Apache's own configuration script after it has
patched the Apache source code. For example, to specify Apache's install
directory and target name and build most modules with all built modules made
into dynamically loadable modules (including mod_ssl), we could put:
# ./configure --with-apache=/usr/local/src/apache_1.3.9 \
--with-ssl=/usr/local/src/openssl-0.9.4
--prefix=/usr/local/apache139 \
--target=httpd139 \
--enable-module=ssl \
--enable-module=most \
--enable-shared=max \
... other APACI options ...
Here --prefix, --target, --enable-module and --enable-shared
options are all passed as options to Apache's configuration
script.
Retaining Use of Apache's configure script with
mod_sslIf mod_ssl is the only module that needs to be configured
externally, it is easy to use the configure script supplied by mod_ssl and use
it to pass APACI options to the Apache configure script. However, if we have
several modules needing special treatment things get more complex - we cannot
drive Apache's configuration from all of them at once.
As an
alternative we can use mod_ssl's configure script to make the EAPI patches to
Apache only, then use Apache's configure script to set up Apache as usual, or go
on to another module and use its configure script. Once Apache is built with
EAPI included we can return to mod_ssl's source code and build it as a loadable
module by telling it to use apxs. The steps to do this are:
1. Build
OpenSSL (and possibly RSAREF)
We first build the OpenSSL libraries, without
installing them. In this case we're building for a site outside the US, so we
have to disable the IDEA cipher:
# cd /usr/local/src/openssl-0.9.4
# ./config no-idea
# make
Alternatively, US sites would use RSAREF (built previously):
# cd /usr/local/src/rsaref-2.0/source
# make -f ../install/unix/makefile
# cd /usr/local/src/openssl-0.9.4
# cp ../rsaref-2.0/source/rsaref.a librsaref.a
# ./config rsaref
# make
2. Patch Apache's source code
Next we need to patch the
extended API that mod_ssl needs into Apache, but without running Apache's
configuration script.
# cd /usr/local/mod_ssl-2.4.1-1.3.9
# ./configure --with-apache=/usr/local/src/apache_1.3.9 --with-eapi-only
3. Do other third-party module preparations
We can now go
to other modules with non-trivial installation procedures and carry out any
necessary preparations. Note that some modules (mod_php being one) need to be
built after the mod_ssl patches have been applied to work, and need -DEAPI added
to their compiler flags at the configuration stage. For this reason it is always
a better idea to deal with the EAPI patches before handling other third-party
modules.
Some modules, like mod_ssl, can also drive Apache's
configuration from their own configuration scripts, so we could do the rest of
the configuration here if we only had one other module to configure. Otherwise,
we go on to the next step.
4. Configure and build EAPI-patched
Apache
Because we're going to build mod_ssl later we must enable mod_so,
either explicitly with --enable-module=so or implicitly by using
--enable-shared. In this case, we're going to compile all modules as dynamic
modules. We're also going to test this server before we use it in anger, so we
give it a different installation root and target name to distinguish it from the
existing installation.
In order to enable the EAPI interface
required by mod_ssl, we need to enable the EAPI rule which was added to Apache's
configuration options when we patched the source in stage 2.
# cd /usr/local/src/apache_1.3.9
# ./configure --prefix=/usr/local/apache139 --target=httpd139
--sbindir=\$prefix/sbin --enable-module=all --enable-shared=max
--enable-rule=EAPI
# make
# make install
If the source is patched correctly and the EAPI rule has been
activated, we should see -DEAPI included in the list of flags passed to the
compiler during the build process.
5. Build and install mod_ssl with
apxs
Now we can build mod_ssl using apxs. This works because we previously
built Apache with the EAPI patches in place; we don't need to apply them again.
The --with-rsa option is only necessary if we're building with the RSAREF
library.
# cd /usr/local/src/mod_ssl-2.4.1-1.3.9
# ./configure --with-ssl=/usr/local/src/openssl-0.9.4
--with-rsa=/usr/local/src/rsaref-2.0/source/
--with-apxs=/usr/local/apache139/sbin/apxs
# make
# make install
Strangely, although the makefile generated by configure uses
apxs to install libssl.so (the filename under which mod_ssl is created), it does
not add the necessary lines to the configuration file. We can fix this easily
with:
# /usr/local/apache139/sbin/apxs -i -a -n mod_ssl pkg.sslmod/libssl.so
This actually does the installation too, so the make install
is redundant. If we already have the directives in httpd.conf for loading
mod_ssl (from a previous installation, perhaps), make install is just fine, as
well as being shorter to type.
Once mod_ssl is installed and
running in Apache, we can check to see if it is present by generating an
information page with mod_info. If present mod_ssl will announce itself on the
Apache version line.
Basic SSL ConfigurationIn order to have
Apache respond to SSL connections we also need make sure it is listening to port
443, the default port for SSL. By default Apache listens to all ports and all
interfaces, but if we're being more restrained we'll need to put something like:
Port 80
Listen 80
Listen 443
To actually enable SSL we need to tell Apache how and when to
use it, by entering SSL directives into its configuration. mod_ssl provides a
lot of directives, but the ones of crucial importance are:
# Switch on the SSL engine - for Apache-SSL use SSLEnable instead
SSLEngine on
# Specify the server's private key
SSLCertificateKeyFile conf/ssl/www.alpha-complex.com.key
# Specify the certificate for the private key
SSLCertificateFile conf/ssl/www.alpha-complex.com.crt
If we're loading SSL dynamically, these directives must be
located after the LoadModule/AddModule directives for Apache to understand them.
If we put the directives at the server level (that is, outside a virtual host
container), then the entire server will be SSL enabled and ordinary HTTP
connections will no longer work on any port. However, we can also put all three
directives in a IP-based virtual host to enable SSL for one host only; in this
case a host dedicated to port 443, the SSL port:
<VirtualHost 192.168.1.1:443>
ServerName www.alpha-complex.com
DocumentRoot /home/www/alpha-complex
... virtual host directives ...
SSLEngine on
SSLCertificateFile conf/ssl/www.alpha-complex.com.crt
SSLCertificateKeyFile conf/ssl/www.alpha-complex.com.key
</VirtualHost>
<VirtualHost 192.168.1.1:*>
ServerName www.alpha-complex.com
DocumentRoot /home/www/alpha-complex
... virtual host directives ...
</VirtualHost>
In order for Apache to support SSL this is all we need in the
configuration; Apache will accept both unencrypted and encrypted connections for
any page on the server. This is not what we ultimately want, but we can enforce
use of SSL in specific areas, as we will see later. For a proper SSL server we
would probably also want to define SSLRandomFile, as described later. mod_ssl
also supports a range of other SSL directives which we can use to customize SSL
in various ways. For example, a simple and obvious thing to do is enforce the
use of SSL in a specific location, which we can do with:
<Directory /home/www/alpha-complex/secure/>
SSLrequireSSL
</Directory>
This rejects ordinary HTTP connections that try to access
resources in the secure section of the site. We can also automatically redirect
clients to use SSL, as we will see later.
©1998 Wrox Press Limited, US and UK.