A great deal of effort has gone into attempting to make WN as secure as possible. Security has received the highest priority in all design decisions. This is not grounds for WN maintainers to feel they can lessen their vigilance, however. The first thing you should be aware of is that there is a trade-off between security and functionality. You can have high security and restricted functionality or lower security with greater functionality, or something in between. WN is designed to let the maintainer choose the point on this continuum he or she is comfortable with. This document tries to discuss the various options you as a maintainer will have and what the implications of your choices are.
First, it is important to understand possible threats to the integrity of a system running the WN server. There are two types of threat which this document addresses separately: (1) external, from a client or purported client on a remote host, and (2) local, from a user with an account on the server host.
After reading this section you may wish to look at the section "File Ownership and Permissions" in this guide.
The maintainer's objective is to prevent any unauthorized access to (or
alteration of) files on the host system. Programs run on the server with
the CGI/1.1 protocols
cause special problems and are discussed separately below. If you do not
need to use any executable programs you should run the server with the -e
option. This option
disallows any attempt to execute a command on your server and does not
allow any data sent by a client even to be written to a temporary disk
file. In this situation the key to WN security is twofold: no
document is served without explicit permission from the maintainer; and
nothing is written to disk on the server except the log file.
The basic philosophy of WN security is that by default no client requests are granted. Permission to serve a document must be explicitly granted by the maintainer. The WN server keeps a small database in each directory of its data hierarchy which contains information about files to be served from that directory. In particular no document can be served unless explicit permission to serve it is given in such a database.
Note: For more information on these database files the chapter "An Overview of the WN Server" in this guide is a good place to start. These files are very easy to create and maintain. See the chapter "Creating Your WN Data Directory" in this guide.
Despite this strong security foundation several additional steps are prudent. The most important is that the maintainer must assure that no untrusted person has write access to any part of the WN hierarchy. For example an incoming anonymous ftp directory should never be part of a WN hierarchy (better yet don't have one at all), because an attacker might be able to put a database there granting illicit access to some documents on the server system for which the user id running the server has read permission. There are several defenses against such a counterfeit database and we discuss them next.
index.cache
Files
All security control for the WN server resides in the per
directory database files (these files have the default name
index.cache
). Consequently it is extremely important to
guarantee their integrity. There are several command line options for
the server which help protect against counterfeit
index.cache
files.
The -t
or -T
option to
wnd
and wnsd
allow you to specify a trusted
owner or group owner (not both) for index.cache
files. When
invoked with only the -t
argument (or the -T
argument) wnd
or wnsd
will not serve a document
unless the index.cache
file listing it has the prescribed
uid or gid. This uid or gid should be that of the maintainer
not the user id under which wnd
or
wnsd
runs. Indeed, for security reasons if the server has
been started as root
and changed to another uid it will
refuse to use an index.cache
file whose owner is the uid
under which it is running. If on your server all
index.cache
files are created by a single user or a single
group I strongly recommend using the -t
or -T
option.
This added security is weakened somewhat if you use the -u
option which allows
index.cache
files owned by untrusted users, but only permits
them to grant access to files owned by the same user as the
index.cache
file. This option might be appropriate if you
permit users to have their own home page on your server. It would allow
users to serve documents which they own but no others. If both the -u
and the -t
argument are used the -u
takes effect except the
trusted user specified with the -t
option is exempt from
its restrictions. Notice that if neither the -t
or -u
argument is used then a
user with his own home page can make a symbolic link to any file readable
by the server and that document will be served! This is true even if the
linked to document is in a directory with limited
access or is outside the server data hierarchy.
When the server is run it must assume the permissions of some user on the
host. Which user is determined when you run the configure
program
or by defining "#define USER_ID
" in config.h
. It is important that
USER_ID
have as few permissions as possible. On many systems
there is a user called nobody
with minimal permissions. The
numeric user_id of nobody
is a good choice and is the
default choice of the WN configure program. Of course the server
must have read permission on all the files served but it should not have
write permission for any directory or file other than its log files. If
the UNIX syslogd(8)
system
utility for logging is enabled there is not even any need for write
permission on a log file. A good practice is to have all the files in
your hierarchy which you intend to serve be owned by the maintainer or
their creator. They should be world readable (assuming they are for
general consumption) but with restricted write permission. The files in
your hierarchy should not be owned by the user id under which
WN will run.
WN does not by default use the UNIX chroot(8)
system utility to further restrict the files which the server can access.
Doing so would enhance security at the expense of extra work for the
maintainer. The effect of this is to prevent the server from even
internally accessing any file which is not in your data directory. If
you are especially concerned about security you may wish to run one of
the public domain TCP wrappers, such as Wietse Venema's tcp_wrappers
(source code available at ftp://ftp.win.tue.nl/pub/security/tcp_wrappers_7.6.tar.gz
),
in conjunction with WN which will allow you to use the UNIX
chroot(8)
system utility. This can simultaneously enhance
security for other TCP services like the UNIX ftpd(8)
system utility.
Enabling the use of programs run on the server greatly enhances its
functionality but also increases the potential risk of an attack. Many
things which on other servers can only be done with CGI/1.1 programs are built-in
features of WN and hence entail much less risk than they would
as CGI/1.1 programs.
These include imagemaps, a variety of document searches, and serving conditional text based on information in the
client supplied headers. If your needs can be met with these features
then you can disable CGI/1.1 with the -e
option and greatly
improve your security.
However, there are many needs which can only be met by programs. The
greatest danger in their use is that even though the program is under the
control of the maintainer, the arguments passed to it can be set by a
potential attacker. WN supports the CGI/1.1 or "Common Gateway
Interface" protocol (see the chapter "Using CGI
Programs on the WN Server" in this guide) for executing
programs. Under this protocol there are three ways by which arguments
are passed to programs. The first of these is used when processing HTML forms which use the
GET
method. Under this method all arguments are put in
environment variables and the program must extract them from the
environment. Moreover, they have been placed in a URL
encoded format by the browser and must be decoded by the program. Thus
if the request is of type GET
, the arguments are examined to
see if they contain an '=
'. If they do, it is assumed that
this is a CGI/1.1 form
response (something like
"name=John&toppings=pepperoni
"). In this case the
program is executed with no arguments and the argument string is placed
in an environment variable where the program can read it. This is fairly
safe from the server point of view but the program writer must exercise
great care.
The second method is for HTML
forms using the POST
method. In this case everything posted
by the client (in URL-encoded
form) must be sent to the UNIX stdin(3)
stream of the CGI/1.1
program. Thus if the request is of type POST
, information
is read from the client and put in a temporary file on disk. Then the
program is executed with no arguments and its stdin(3)
comes
from this file. Security is the responsibility of the program writer. It
is not so dangerous to have arguments come from stdin(3)
but
the program writer must still exercise care.
Finally if the GET
request has arguments but no
'=
' it is assumed to be an ISINDEX
type request
and the program should be executed with the given arguments. While the
CGI/1.1 specification does
not permit the altering of arguments, it does say that if the arguments
pose any security problems it is permissible to put the string in an
environment variable and execute the program with no arguments, just as
in the CGI/1.1 forms case
described above. WN takes a very strict view on this subject
and considers any characters other than space and alphanumeric characters
as a security problem. Accordingly, if it finds any other character in
an argument it will put all arguments in the appropriate environmental
variable and run the program with no command line arguments.
Again let me say the program writer must exercise great care. I can't emphasize this too strongly. When you run a CGI/1.1 program the server almost completely absolves itself of security responsibility and dumps that responsibility on the program writer. Most authors of freely distributed CGI/1.1 programs are not fully cognizant of potential security holes they may open up. Running insecure programs created locally or obtained from Usenet postings is almost certainly the single greatest risk to a WN server site. To find out more about writing secure CGI/1.1 programs I strongly recommend that you read the relevant sections of the "WWW Security FAQ" maintained by Lincoln Stein and the "Safe CGI Programming" maintained by Paul Phillips.
Whenever untrusted users have accounts on a system there is risk involved. The objective of WN is to insure that running the server does not increase this risk. If the server is wisely managed, I believe this goal can be achieved. Here are some guidelines.
If it is possible make sure that no untrusted user has write access to
any part of your WN hierarchy. As mentioned above an attacker
with write access to your hierarchy can create an
index.cache
file which will give access to anything on your
server which is readable by the user id under which WN runs.
Even worse, she can create a shell program and a index.cache
file permitting it to be executed, so it can be executed with all the
permissions of that user id. A good rule of thumb is:
Note: Always assume that everyone with write access to any part of your data hierarchy has all the permissions of the user id under which your server runs!
This should not be true if you are using some of the command line options described above, but it is good practice to behave as if it were true.
Sometimes it is not possible or desirable to deny write access to your WN hierarchy. For example, you may need to allow all users to have a home page in their home directory or in some other designated place. There are two important things to do in this case.
The first of these is run the server with the -u
option. This has the
effect of requiring that every file served (including wrappers and includes) have the same owner as the
index.cache
file which grants it permission to be served.
This means that untrusted users can only serve files which they own.
This will prevent a user from serving the UNIX passwd(5)
configuration file typically in /etc
, but will not prevent
him from making his own copy of passwd(5)
and serving that.
If the -t
or -T
option is also used then
index.cache
files owned by the trusted user or trusted group
are exempt from this requirement and they may grant permission to serve
any file the server can read. For security reasons the server will
refuse to use an index.cache
file which is a symbolic link
to another file.
The -e
or -E
option mentioned above are also a good idea in
this case, to prevent any execution of programs or at least restrict
their execution to trusted index.cache
files.
You should note that when run in its default configuration there is no
way to use access files or password authentication to prevent
users on your system, who can create index.cache
files, from
gaining access to files you are serving. They can simply make a symbolic
link in their part of the hierarchy to the file you want to restrict and
a index.cache
file permitting it to be served. Since the
server has access to the restricted file it will serve it if it is listed
in a index.cache
file. This simple threat can be avoided by
using the -u
option
described above, but the number of potential threats is quite large. For
example, if the -e
or -E
option is not used a
hostile user could write a CGI/1.1 program which reads
the sensitive files and mails them to himself. In general I would
strongly advise against trying to have sensitive documents (protected by
password or .access
files) and
potentially hostile users on the same server. I would also strongly
advise against allowing potentially hostile CGI/1.1 programs, executed
includes or external modules. They can be disallowed through the use of
the -e
or -E
options. If they are
not disallowed a CGI/1.1
program can alter or destroy log files. A hostile authorization module
could collect user passwords.
The -u
and -E
options greatly enhance
security, but it is important to keep the following principle in mind.
You should assume that any permissions you grant to the user id under
which WN runs are also granted to every user who can create an
index.cache
file in your data hierarchy.
WN offers two methods of limiting access to your hierarchy or parts of it. See the chapter "Limiting Access to Your WN Hierarchy" in this guide for information on how to use these features.
These are useful for many purposes but I would not advise using them to protect extremely sensitive information. The first of these methods is restriction by hostname or IP address. It is not impossible to spoof a server with a fake IP address, but I think it is fairly difficult. It is easier to use a counterfeit hostname. For this reason I would suggest using IP addresses rather than host names in access control files.
The other method of limiting access is by password with the HTTP/1.1 Basic Authentication
scheme. This is about as secure as using passwords with the UNIX ftpd(8)
system utility to protect information. This scheme is flawed in that it
involves the transmission of essentially unencoded passwords over the
network. It is relatively easy for unscrupulous people to obtain
"sniffer" software which allows eavesdropping on all local network
traffic. This means, in particular, that it is possible to intercept
passwords of other users.
For security reasons when you use wnauth
or any "Authorization-Module=
"
you are required to use either the -t
or -T
option or the -a
or -A
option when the
server is run and to have the index.cache
file in the
protected directory owned by the trusted user or group. This is to guard
against counterfeit authentication modules.
This particular problem is remedied by the "Digest" authentication scheme. Digest authentication is supported experimentally by WN but has the rather severe drawback that no publicly available clients currently support it. It is experimental, because I have no client to test it and hence it has barely been tested. I believe it will be a standard part of HTTP/1.1 and at that time will significantly improve security of password protected directories.
The directive "Authorization-Realm=
",
used whenever an authentication module is used, is to notify the client
that for any document on this server with the same realm as this one, the
same password/username combination will be valid, so the client need not
ask the user for a username and password, but can reuse the one supplied
for the first document with this realm. For security reasons you should
always put your host and domain name in the realm. This may at least
discourage attempts at other sites to forge your realm in order to
collect user passwords. Your users should also be warned never to enter
their password if the realm displayed when they are prompted for a
password contains a different hostname than the one in the URL they are
trying to access.
Both Basic authentication and access control by IP address become much
more vulnerable if the potential attack comes from users who can create
index.cache
files for another part of your server's data
hierarchy. I would recommend against trying to use either to protect
information from users with home pages on your server.
If no potentially hostile users can create documents which can be served on your system the mechanisms described above provide protection adequate for many purposes. If I were an information provider selling access to a collection of information on my server, I would be comfortable using the numeric IP address to limit access to my paying customers. On the other hand I would not want any of these mechanisms used to protect my bank records.
This a list of possible ways you might configure your server by setting
values in config.h
and using
command line arguments. It assumes that you are running either
wnsd
or wnd
on the privileged port 80 and that
the default value of "#define USERID
" and
"#define GROUPID
" defined
in config.h
have not been
changed. This will mean that wnsd
will be started as
root
, but will almost immediately switch its privileges to
those of the unprivileged user nobody
. Likewise if
wnd
is running under the UNIX inetd(8)
system utility we assume that it is set to run with the privileges of
nobody
.
The following list of configurations is in decreasing order of security.
This strongest level of security is achieved by running either
wnsd
(or wnd
under the UNIX inetd(8)
system utility) with the -t
or -T
option and with the
-e
option and with
no other options. For the really paranoid uncommenting the "#define FORBID_CGI
"
line in the file config.h
and recompiling
removes the CGI/1.1
code from the binary.
With these options no CGI/1.1 programs or
filters or program output includes are permitted. Also the
POST
method is not accepted (an error is returned for a
POST
request). Furthermore only
index.cache
files owned by the user specified in the -t
option are used.
The server should be run as nobody
(the default) and the
numeric user id specified with -t
option should be the
maintainer's.
This is the the strongest level of security if you need the
functionality of CGI/1.1 programs or
filters or program output as server includes. This security
configuration does not allow any user home pages (unless the
maintainer produces the index.cache
file for them). To
use this level run wnsd
(or wnd
under
inetd(8)
) with the -t
or -T
option and no other
options. This places all control in the hands of a single maintainer
or a "maintainer group". No document or program output may be served
unless the maintainer has authorized it by explicit mention in one of
the index.cache
database files. The server will not
recognize any index.cache
file unless it is owned by the
maintainer specified with the -t
option or the group
specified with the -T
option. Only one of
-t
or -T
options can be used.
This permits users on the server host to have and control their own
home pages and documents, but with a number of limitations. They
will not be permitted to run CGI/1.1 programs, filters
or include programs. Also the server will require that every file
served (including wrappers and includes) have the same owner as the
index.cache
file which grants it permission to be
served. This means that users can only serve files which they own.
This is configuration is obtained by running with the -E
option and the -u
option. The -E
option is similar to
the -e
option except
that index.cache
files owned by a trusted user id or
trusted group id (set with the -t
or -T
option) are exempt
from the restrictions. The -u
option requires that
in order to be served a file must be owned by the owner of the
index.cache
file which lists it. Trusted users as
specified with -t
or
-T
options are
exempt from this restriction also.
One of the security problems encountered with another HTTP server
involved an attack by overflowing an internal buffer with data provided
by the the client in such a way that the (attacking) client could supply
code that the server executed. I have, to the best of my ability,
defended against this in WN code. All copying of data supplied
by the client and most copying of data read from the
index.cache
file is done by a function which I wrote and
which was designed precisely to deal with this threat. Excess data which
would overflow is discarded so buffers may contain truncated data, but
will not be overwritten.
Probably the most controversial security "feature" of WN is that
it greatly restricts the set of characters which can be used in file or
path names. Instead of trying to decide which characters are dangerous
and disallow them, WN has a list of characters presumed safe and
only allows them. The currently allowed characters are alphanumeric
characters and '_
', '-
', '.
',
'+
', '/
' and '%
'. The same
restrictions are applied to the PATH_INFO
part of URLs for
CGI/1.1 programs, except
that the character '=
' is also allowed. These restrictions
sometimes cause problems with CGI/1.1 programs that like to
include unusual characters in file names or PATH_INFO
.
Also the server will attempt to resolve all "../
" references
while staying in the server data hierarchy. If these references would
result in a request for a document outside the server data hierarchy the
request is treated like a request containing illegal path characters. In
particular with verbose logging turned
on, a message like "SECURITY Found bad character (%X hex) in
path
" is logged.
To defend against a "denial of service" attack the server will refuse a
POST
request with post data in excess of 5 megabytes. This
does not defend against multiple requests with large POST
data. The maximum allowed size of POST
data can be altered
by changing the value of MAX_POST
in the file
wn/wn.c