WN home page

Version 2.5.0
[Previous] [Next] [Up] [Top] [Search] [Index]

Security on the WN Server


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.

4.1 External Threats

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.

4.1.1 Protecting Your 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.

4.1.2 CGI Programs

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.

4.2 Internal Threats

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.

4.3 Password Authentication and Restriction by IP Address

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.

4.4 Some Recommended Security Configurations

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.

4.4.1 Forbid CGI and Only Maintainer Trusted

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.

4.4.2 Only Maintainer or Maintainer Group Trusted

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.

4.4.3 Restricted User Serving Privileges

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.

4.5 Other WN Security Measures

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 10 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_LEN in the file config.h


WN version 2.5.0
Copyright © 1998-2005 John Franks <john@math.northwestern.edu>
licensed under the GNU Free Documentation License
Last modified: Sat June 18 2005
[Previous] [Next] [Up] [Top] [Search] [Index]