The vulnerability of servers running scripts is a continual source of concern to the Apache Group. Unix systems provide a special method of running CGIs that gives much better security via a wrapper . A wrapper is a program that wraps around another program to change the way it operates. Usually this is done by changing its environment in some way; in this case, it makes sure it runs as if it had been invoked by an appropriate user. The basic security problem is that any program or script run by Apache has the same permissions as Apache itself. Of course, these permissions are not those of the superuser, but even so, Apache tends to have permissions powerful enough to impair the moral development of a clever hacker if he could get his hands on them. Also, in environments where there are many users who can write scripts independently of each other, it is a good idea to insulate them from each other’s bugs, as much as is possible.
suEXEC reduces this risk by changing the permissions given to a program or script launched by Apache. To use it, you should understand the Unix concepts of user and group execute permissions on files and directories. suEXEC is executed whenever an HTTP request is made for a script or program that has ownership or group-membership permissions different from those of Apache itself, which will normally be those appropriate to webuser of webgroup.
The documentation says that suEXEC is quite deliberately complicated so that “it will only be installed by users determined to use it.” However, we found it no more difficult than Apache itself to install, so you should not be deterred from using what may prove to be a very valuable defense. If you are interested, please consult the documentation and be guided by it. What we have written in this section is intended only to help and encourage, not to replace the words of wisdom. See http://httpd.apache.org/docs/suexec.html.
To install suEXEC to
run with the demonstration site site.suexec, go
to the support subdirectory below the location
of your Apache source code. Edit suexec.h to
make the following changes to suit your installation. What we did, to
suit our environment, is shown marked by
/**CHANGED**/
:
/* * HTTPD_USER -- Define as the username under which Apache normally * runs. This is the only user allowed to execute * this program. */ #ifndef HTTPD_USER #define HTTPD_USER "webuser" /**CHANGED**/ #endif /* * UID_MIN -- Define this as the lowest UID allowed to be a target user * for suEXEC. For most systems, 500 or 100 is common. */ #ifndef UID_MIN #define UID_MIN 100 #endif
The point here is that many systems have “privileged” users below some number (e.g., root, daemon, lp, and so on), so we can use this setting to avoid any possibility of running a script as one of these users:
/* * GID_MIN -- Define this as the lowest GID allowed to be a target group * for suEXEC. For most systems, 100 is common. */ #ifndef GID_MIN #define GID_MIN 100 // see UID above #endif
Similarly, there may be privileged groups:
/* * USERDIR_SUFFIX -- Define to be the subdirectory under users' * home directories where suEXEC access should * be allowed. All executables under this directory * will be executable by suEXEC as the user so * they should be "safe" programs. If you are * using a "simple" UserDir directive (ie. one * without a "*" in it) this should be set to * the same value. suEXEC will not work properly * in cases where the UserDir directive points to * a location that is not the same as the user's * home directory as referenced in the passwd file. * * If you have VirtualHosts with a different * UserDir for each, you will need to define them to * all reside in one parent directory; then name that * parent directory here. IF THIS IS NOT DEFINED * PROPERLY, ~USERDIR CGI REQUESTS WILL NOT WORK! * See the suEXEC documentation for more detailed * information. */ #ifndef USERDIR_SUFFIX #define USERDIR_SUFFIX "/usr/www/APACHE3/cgi-bin" /**CHANGED**/ #endif /* * LOG_EXEC -- Define this as a filename if you want all suEXEC * transactions and errors logged for auditing and * debugging purposes. */ #ifndef LOG_EXEC #define LOG_EXEC "/usr/www/APACHE3/suexec.log" /**CHANGED**/ #endif /* * DOC_ROOT -- Define as the DocumentRoot set for Apache. This * will be the only hierarchy (aside from UserDirs) * that can be used for suEXEC behavior. */ #ifndef DOC_ROOT #define DOC_ROOT "/usr/www/APACHE3/site.suexec/htdocs" /**CHANGED**/ #endif /* * SAFE_PATH -- Define a safe PATH environment to pass to CGI executables. * */ #ifndef SAFE_PATH #define SAFE_PATH "/usr/local/bin:/usr/bin:/bin" #endif
Compile the file to make suEXEC executable by typing:
make suexec
and copy it to a sensible location (this will very likely be different on your site — replace /usr/local/bin with whatever is appropriate) alongside Apache itself with the following:
cp suexec
/usr/local/bin
You then have to set its permissions properly by making yourself the superuser (or persuading the actual, human superuser to do it for you if you are not allowed to) and typing:
chown root /usr/local/bin/suexec chmod 4711 /usr/local/bin/suexec
The first line gives suEXEC the owner
root; the second sets the
setuserid
execution bit for file modes.
You then have to tell Apache where to find the suEXEC executable by editing . . . src/include/httpd.h. Welooked for “suEXEC” and changed it thus:
/* The path to the suExec wrapper; can be overridden in Configuration */ #ifndef SUEXEC_BIN #define SUEXEC_BIN "/usr/local/bin/suexec" /**CHANGED**/ #endif
This line was originally:
#define SUEXEC_BIN HTTPD_ROOT "/sbin/suexec"
Notice that the macro HTTPD_ROOT
has been removed.
It is easy to leave it in by mistake — we did the first time
around — but it prefixes /usr/local/apache
(or whatever you may have changed it to) to the path you type in,
which may not be what you want to happen. Having done this, you
remake Apache by getting into the .../src
directory and typing:
make cp httpd /usr/local/bin
or wherever you want to keep the executable. When you start Apache, nothing appears to be different, but a message appears in .../logs/error_log :[8]
suEXEC mechanism enabled (wrapper: /usr/local/bin/suexec)
We think that something as important as suEXEC should have a clearly visible indication on the command line and that an entry in a log file is not immediate enough.
To turn suEXEC off, you simply remove the executable or, more cautiously, rename it to, say, suexec.not. Apache then can’t find it and carries on without comment.
Once suEXEC is running, it applies many tests to
any CGI or server-side include (SSI) script invoked by Apache. If any
of the tests fail, a note will appear in the
suexec.log file that you specified (as the macro
LOG_EXEC
in suexecx.h) when
you compiled suEXEC. A comprehensive list
appears in the documentation and also in the source. Many of these
tests can only fail if there is a bug in Apache,
suEXEC, or the operating system, or if someone
is attempting to misuse suEXEC. We list here the
notes that you are likely to encounter in normal operation, since you
should never come across the others. If you do, suspect the
worst:
Does the target program name have a “/” or “..” in its path? These are unsafe and not allowed.
Does the user who owns the target script exist on the system? Since user IDs can be deleted without deleting files owned by them, and some versions of tar, cpio, and the like can create files with silly user IDs (if run by root), this is a sensible check to make.
Does the group to which this user belongs exist? As with user IDs, it is possible to create files with nonexistent groups.
Is the user not the superuser? suEXEC won’t let root execute scripts online.
Is the user ID above the minimum ID number specified in suexec.h ? Many systems reserve user IDs below some number for certain powerful users — not as powerful as root, but more powerful than mere mortals — e.g., the lpd daemon, backup operators, and so forth. This allows you to prevent their use for CGIs.
Is the user’s group not the superuser’s group? suEXEC won’t let root’sgroup execute scripts online.
Is the group ID above the minimum number specified? Again, this is to prevent the misuse of system groups.
Is this directory below the server’s document root,
or, if for a UserDir
, is the directory below the
user’s document root?
Is this directory not writable by anyone else? We don’t want to open the door to everyone.
Does the target script exist? If not, it can hardly be run.
Is it only writable by the owner?
Is the target program not setuid or setgid ? We don’t want visitors playing silly jokes with permissions.
Is the target user the owner of the script?
If all these hurdles are passed, then the program executes. In setting up your system, you have to bear these hurdles in mind.
Note that once suEXEC has decided it will
execute your script, it then makes it even safer by cleaning the
environment — that is, deleting any environment variables not on
its list of safe ones and replacing the PATH
with
the path defined in SAFE_PATH
in
suexec.h. The list of safe environment variables
can be found in .../src/support/suexec.c in the
variable safe_env_lst
. This list includes all the
standard variables passed to CGI scripts. Of course, this means that
any special-purpose variables you set with SetEnv
or PassEnv
directives will not make it to your CGI
scripts unless you add them to suexec.c.
[8] In v1.3.1
this message didn’t appear unless you included the
line LogLevel
debug
in your
Config file. In later versions it will appear automatically.