Help secure your web applications with mod_ssl and suEXEC.
Web server security is a very important issue these days, especially since people are always finding new and creative ways to put the Web to use. If you're using any sort of web application that needs to handle authentication or provides some sort of restricted information, you should seriously consider installing a web server with SSL capabilities. Without SSL, any authentication information your users send to the web server is sent over the network in the clear, and any information that clients can access can be viewed by anyone with a sniffer. If you are already using Apache, you can easily add SSL capabilities with mod_ssl (http://www.modssl.org).
In addition, if your web server serves up dynamic content for multiple users, you may want to enable Apache's suEXEC functionality. suEXEC allows your web server to execute server-side scripts as the user that owns them, rather than as the account under which the web server is running. Otherwise, any user could create a script and run code as the account the web server is running under. This is a bad thing, particularly on a multiuser web server. If you don't review the scripts that your users write before allowing them to be run, they could very well write code that allows them to access other users' data or other sensitive information, such as database accounts and passwords.
To compile Apache with mod_ssl, download the appropriate mod_ssl source distribution for the version of Apache that you'll be using. (If you don't want to add mod_ssl to an existing Apache source tree, you will also need to download and unpack the Apache source.) After you've done that, unpack the mod_ssl distribution and go into the directory that it created. Then run a command like this:
# ./configure \ --with-apache=../apache_1.3.29 \ --with-ssl=SYSTEM \ --prefix=/usr/local/apache \ --enable-module=most \ --enable-module=mmap_static \ --enable-module=so \ --enable-shared=ssl \ --disable-rule=SSL_COMPAT \ --server-uid=www \ --server-gid=www \ --enable-suexec \ --suexec-caller=www \ --suexec-uidmin=500 \ --suexec-gidmin=500
This will both patch the Apache source tree with extensions provided with mod_ssl and configure Apache for the build process.
You will probably need to change a number of options in order to build Apache. The directory specified in the --with-apache switch should point to the directory that contains the Apache source code for the version that you are building. In addition, if you want to use a version of OpenSSL that has not been installed yet, specify the location of its build tree with the --with-ssl switch. If you elect to do that, you should configure and build OpenSSL in the specified directory before attempting to build Apache and mod_ssl. The --server-uid and --server-gid switches are used to specify what user and group the web server will run under. Apache defaults to the "nobody" account. However, many programs that can be configured to drop their privileges also default to the nobody account; if you end up accepting these defaults with every program, the nobody account can become quite privileged. So, it is recommended that you create a separate account for every program that provides this option.
The remaining options enable and configure Apache's suEXEC. To provide the suEXEC functionality, Apache uses a SUID wrapper program to execute users' scripts. This wrapper program makes several checks before it will allow a program to execute. One thing that the wrapper checks is the UID of the process that invoked it. If it is not the account that was specified with the --suexec-caller option, then execution of the user's script will abort. Since the suEXEC wrapper will be called by the web server, this option should be set to the same value as --server-uid. Additionally, since most privileged accounts and groups on a system usually all have a UID and GID beneath a certain value, the suEXEC wrapper will check to see if the UID or GID of the process invoking it is less than this threshold. For this to work, you must specify the appropriate value for your system. In this example, Apache and mod_ssl are being built on a Red Hat system, which starts regular user accounts and groups at UID and GID 500. In addition to these checks, suEXEC performs a multitude of other checks, such as ensuring that the script is writable only by the owner, that the owner is not root, and that the script is not SUID or SGID.
After the configure script completes, change to the directory that contains the Apache source code and run make and make install. You can run make certificates if you would like to generate an SSL certificate to test out your installation. You can also run make certificate TYPE=custom to generate a certificate signing request to be signed by either a commercial Certificate Authority or your own CA. See [Hack #45] if you would like to run your own Certificate Authority.
After installing Apache, you can start it by running this command:
# /usr/local/apache/bin/apachectl startssl
If you want to start out by testing it without SSL, run this:
# /usr/local/apache/bin/apacectl start
You can then verify that suEXEC support is enabled by running this command:
# grep suexec /usr/local/apache/logs/error_log [Thu Jan 1 16:48:17 2004] [notice] suEXEC mechanism enabled (wrapper: /usr/local/apache/bin/suexec)
Now add a Directory entry similar to this to enable CGI scripts for user directories:
<Directory /home/*/public_html> AllowOverride FileInfo AuthConfig Limit Options MultiViews Indexes SymLinksIfOwnerMatch Includes ExecCGI <Limit GET POST OPTIONS PROPFIND> Order allow,deny Allow from all </Limit> <LimitExcept GET POST OPTIONS PROPFIND> Order deny,allow Deny from all </LimitExcept> </Directory>
In addition, add this line to enable CGI scripts outside of the ScriptAlias directories:
AddHandler cgi-script .cgi
After you've done that, you can restart Apache by running this:
# /usr/local/apache/bin/apachectl restart
Now test out suEXEC with a simple script that runs the id command, which will print out information about the user the script is executed as:
#!/bin/sh echo -e "Content-Type: text/plain\r\n\r\n" /usr/sbin/id
Put this script in a directory such as /usr/local/apache/cgi-bin, name it suexec-test.cgi, and make it executable. Now enter the URL for the script (i.e., http://webserver/cgi-bin/suexec-test.cgi) into your favorite web browser. You should see something like this:
uid=80(www) gid=80(www) groups=80(www)
As you can see, it is being executed as the same user that the web server runs as.
Now copy the script into a user's public_html directory:
$ mkdir public_html && chmod 711 ~/ ~/public_html $ cp /usr/local/apache/cgi-bin/suexec-test.cgi .
After you've done that, enter the URL for the script (i.e., http://webserver/~user/suexec-test.cgi) in your web browser. You should see something similar to this:
uid=500(andrew) gid=500(andrew) groups=500(andrew)
In addition to handling scripts in users' private HTML directories, suEXEC can also execute scripts as another user within a virtual host. However, to do this, you will need to create all of your virtual host's directories beneath the web server's document root (i.e., /usr/local/apache/htdocs). When doing this, you can configure what user and group the script will execute as by using the User and Group configuration directives within the VirtualHost statement.
<VirtualHost> User myuser Group mygroup DocumentRoot /usr/local/apache/htdocs/mysite ... </VirtualHost>
Unfortunately, suEXEC is incompatible with mod_perl and mod_php because the modules run within the Apache process itself instead of a separate program. Since the Apache process is running as a nonroot user it cannot change the UID under which the scripts execute. suEXEC works by having Apache call a special SUID wrapper (e.g., /usr/local/apache/bin/suexec) that can only be invoked by Apache processes. If you care to make the security/performance trade-off by using suEXEC but still need to run Perl scripts, you can do so through the standard CGI interface. Just as with Perl, you can also run PHP programs through the CGI interface, but you'll have to create a php binary and specify it as the interpreter in all the PHP scripts you wish to execute through suEXEC. You can also execute your scripts through mod_perl or mod_php by locating them outside the directories where suEXEC will work.