By Tim Schürmann
Hugo Leisink was frustrated. Although he had already tried out various web servers, none of them were really convincing. In his opinion, the configuration tools were cryptic and the security features were limited. Leisink's concerns about the state of the web server craft prompted him to develop his own web server in January 2002.
The end of the story is Hiawatha, a light web server with good performance and some innovative security functions. Hiawatha's small size of just 600KB makes it perfect for deployment on embedded devices or less powerful machines.
Hiawatha is easy to install: Just download the current package from the homepage [1], unpack it, and run the typical set of three commands:
./configure make sudo make install
Hiawatha's minimum requirements are a C compiler and the libc6 (alias glibc2) library (typically libc6-dev, or glibc-devel). If any other dependencies are missing, the configure script will not warn you, but will, instead, simply disable the corresponding functionality.
Thus, it is a good idea to have a quick look at the log created by the script. If you don't have the OpenSSL library (libssl), you will have to do without encryption, and thus https connections. XSLT (Extensible Stylesheet Language Transformations) support is also optional; you need the --enable-xslt configure parameter and the libxslt library to tell the web server to use XSLT.
Hiawatha parses all of its settings from a single, small configuration file called httpd.conf, which resides in the /usr/local/etc/hiawatha directory by default. httpd.conf has some useful defaults and a number of commented lines you can use as templates, but you should give it a quick check to make sure the settings are correct before you run the web server for the first time.
Additionally, you can simply create a new configuration file on the fly - a feat that would make Apache stand back in amazement. Before you save a new configuration file, make sure you rename the original httpd.conf so you will have a working configuration to fall back on if you have problems.
The httpd.conf file starts by telling the web server which port on which network interface to listen on for incoming requests. The port is handled by the binding:
Binding { Port = 80 Interface = 192.169.2.123 }
This command tells Hiawatha to listen on the network interface with the IP address of 192.169.2.123 for incoming requests using the default port for web servers (port 80). As the example shows, the structure of the configuration file is really simple: The web server expects exactly one setting in each line, and each setting comprises a name, an equals sign, and the matching value.
To bind Hiawatha to another interface, simply add a second Binding section, as follows:
Binding { Port = 443 Interface = 192.168.2.124 }
If you want the web server to listen for requests on all your network interfaces, a single Binding section without an Interface specification will suffice.
The next thing Hiawatha needs to know is which website to serve up. To define the website, you first specify the subdirectory with the files. Apache users will be familiar with this directory as DocumentRoot, but Hiawatha calls it WebsiteRoot:
WebsiteRoot = /usr/local/var/www/hiawatha
In principle, you can select any folder on your disk; you will find a sample index.html file below /usr/local/var/www/hiawatha. Hiawatha needs the name (or alternatively the IP address) on which the website will be accessible:
Hostname = www.mywebsite.com
This detail is particularly important if you are using virtual hosts (see the box titled "Virtual Hosts" for more details). If you use IPv6 addresses, just use them; you can even mix them with IPv4 addresses.
That's it. This minimal configuration contains just six lines. Listing 1 is a complete httpd.conf file. Comments start with a pound sign, as in shell scripts.
Listing 1: Minimal Configuration for Hiawatha |
01 # Listen for requests on port 80 of the network interface with IP address IP 192.168.2.123: 02 Binding { 03 Port = 80 04 Interface = 192.168.2.123 05 } 06 07 # Serve up the following page: 08 WebsiteRoot = /usr/local/var/www/hiawatha 09 Hostname = localhost |
Just to see whether the configuration is working, launch the web server with the following command:
sudo hiawatha
If you receive an error message:
Error binding IP_address
either Hiawatha does not have sufficient privileges (for ports below 1024) or a competing web server is already listening on the same port. A competing web server is actually a common occurrence if you are using a distribution that comes with a pre-configured web server, such as Apache. In that case, you can either change the port or stop the competitor. To stop Apache in Ubuntu, for example, you could enter the command
sudo /etc/init.d/apache2 stop
although you might still see an error message:
Warning: can't write PID file /usr/local/var/run/hiawatha.pid
The preceding message says that Hiawatha does not have access privileges for the /usr/local/var/run directory; one common cause for this message is that the directory just doesn't exist. You can either create the directory manually or live with the error message for the time being. The web server simply stores its process ID in the specified PID file. Alternatively, you can use httpd.conf to point to a different file location:
PIDFile=<filename>
Launching a browser and pointing to localhost will tell you if Hiawatha is running properly. You should see the test page shown in Figure 1.
A kill signal, as in
<C>sudo killall hiawatha<C>
will stop Hiawatha. Of course, this is a fairly brutal approach, and it is not very elegant if you are thinking of adding the web server startup to your distribution's boot process. The hiawatha script included in the extras subdirectory below the source code directory gives you a more elegant approach to launching and stopping Hiawatha, but you should be aware of a couple of obstacles. First, the script assumes that the web server was able to create the PID file. Also, the script is designed for Debian. If you want to run the script on any other distribution, you need to modify the paths in the first four lines to match your local conditions.
As you would expect of a modern web server in these Web 2.0 times, Hiawatha supports the execution of CGI programs. Of course, the administrator first has to explicitly enable this feature
ExecuteCGI = yes
and then specify which file suffix the CGI programs will have:
CGIextension = cgi
In the case of scripts, such as PHP or Python applications, Hiawatha also needs the name and path for the interpreter:
CGIhandler = /usr/bin/php5-cgi:php,php5
When Hiawatha finds a file with a .php or .php5 suffix, it will launch the php5-cgi interpreter in the /usr/bin folder and pass the script in to it. The same approach is used for other script languages:
CGIhandler = /usr/bin/perl:pl CGIhandler = /usr/bin/python:py
To prevent buggy or malicious CGI programs or scripts from crashing or hijacking the computer, you should restrict their run time. A value of five seconds should do for a start:
TimeForCGI = 5
The settings thus far have produced a basic web server with very little fancy stuff. You still haven't seen much of Hiawatha's advanced security features. Before touring these additional options, start by telling Hiawatha to talk to the logfiles:
SystemLogfile = /usr/local/var/log/hiawatha/system.log AccessLogfile = /usr/local//var/log/hiawatha/access.log ErrorLogfile = /usr/local//var/log/hiawatha/error.log GarbageLogfile = /usr/local//var/log/hiawatha/garbage.log
The SystemLogfile holds the messages from the daemon; access is logged in AccessLogfile, and ErrorLogfile logs errors. The last line collects the garbage - that is, erroneous or incomplete HTTP requests. Incomplete and erroneous requests are often an indication of a break-in attempt.
Thus far, the web server has only listened on port 80. To bind to this port, Hiawatha needs root privileges. However, it is not a good idea to leave the program running as root. To avoid this problem, Hiawatha changes the user to nobody immediately after launching. The ServerId setting tells the web server to change to another user:
ServerId = www-data
The next step is to mitigate the danger of denial-of-service attacks (DoS) by reducing the number of simultaneous connections that Hiawatha can handle - both overall and per IP address:
ConnectionsTotal = 150 ConnectionsPerIP = 10
While you're at it, it is also a good idea to limit the internal cache size to, say, 15MB:
CacheSize = 15
Also, you can tell Hiawatha to restrict the cache to files ranging in size from CacheMaxFilesize (in kilobytes) to CacheMinFilesize (in bytes):
CacheMaxFilesize = 128 CacheMinFilesize = 256
In the opinion of Hiawatha developer Hugo Leisink, clients should behave well if they want the web server to answer them. To punish clients that send malformed or overlong HTTP requests, Hiawatha resorts to the medieval method of banning. For example, with the command
BanOnGarbage = 300
Hiawatha will refuse to respond to a client for 300 seconds if it sends a non-standards-compliant HTTP request, and
BanOnMaxReqSize = 60
bans it for 60 seconds in the case of a request with an illegal length. You can combat flooding with the following command:
BanOnFlooding = 10/1:35
This command bans a client for 35 seconds if it has sent more than 10 request to Hiawatha within a second. The following is also useful:
BanOnCMDi = 60
This setting bans a client for 60 seconds if it has attempted a command injection attack. The following does the same for SQL injection attacks:
BanOnSQLi = 70
Hiawatha also supports blacklists or whitelists:
BanlistMask = allow 192.168.2.111, deny 192.168.0.0/16
If a banned client is really naughty and attempts to access Hiawatha again while exiled, the following command automatically resets the ban:
RebanDuringBan = yes
For confidential data, you should always use a secure SSL connection. Before Hiawatha can speak https, you need an X509 SSL certificate, which you can either buy from a trusted third party (i.e., a Certificate Authority) or create yourself with the use of OpenSSL [2]. The commands to accomplish this are shown in Listing 2.
Listing 2: Creating an X509 SSL Certificate |
01 openssl genrsa -out serverkey.pem 2048 02 openssl req -new -x509 -days 3650 -key serverkey.pem -out server.crt 03 echo "" >> serverkey.pem 04 cat server.crt >> serverkey.pem 05 echo "" >> serverkey.pem 06 rm -f server.crt |
The result of this is a serverkey.pem file, which you need to store along with httpd.conf (typically in /usr/local/etc/hiawatha).
Https connections are typically directed at port 443; the web server thus needs to listen on this port and grab the certificate when it receives a request:
Binding { Port = 443 Interface = 192.168.2.123 UseSSL = yes ServerKey = /usr/local/etc/hiawatha/serverkey.pem }
The preceding entry means that browsers can only use the https protocol to set up a connection to Hiawatha by way of port 443; in this example, the result would be https://192.168.2.123:443. Additionally, the certificate is only valid for the specified port and interface combination. To use it for all secure connections, put the last line behind the closing bracket.
CGI programs are popular targets for attackers, possibly because they are buggy, or because the developer has been lazy with respect to security. To prevent CGI programs from running amok and even taking the web server down, Hiawatha can use a CGI wrapper to confine them. The wrapper will give CGI programs a different user ID if needed.
To set up the jail, you first need to select a directory as your CGI root; the CGI root directory contains all CGI programs and scripts. To match Listing 1, the directory could be /usr/local/var/www/hiawatha/cgi. The wrapper will only run CGI programs and scripts from this directory.
Next you need another configuration file called cgi-wrapper.conf. This file resides in the same directory as httpd.conf - that is, /usr/local/etc/hiawatha. The Hiawatha archive includes a sample of cgi-wrapper.conf with all the lines commented out.
The cgi-wrapper.conf first tells the wrapper what programs it is allowed to run outside the CGI root directory. The list of permissible programs might include interpreters for the script languages you use:
CGIhandler = /usr/bin/php5-cgi CGIhandler = /usr/bin/perl
Note that CGIhandler is not a good choice of name because this setting has very little in common with the identically named setting in httpd.conf. Once you have configured the wrapper, you can lock away your CGI programs:
Wrap = wrap_id; /usr/local/var/www/hiawatha/cgi; tim
The name of the jail is at the start of the line. Because you will need to add this name to your httpd.conf file, you need to keep it in mind. Following the first semicolon, you have the name of the CGI root directory and then finally the username (or ID) under which CGI programs will be running. If the directory name contains a pipe symbol, as in the following line,
Wrap = wrap_id; /usr/local/var/www/hiawatha|cgi; tim
the CGI wrapper will use the part before the pipe as a chroot directory and put everything else into this environment. In this case, you will need to make sure the CGI handlers are available in the chroot directory.
The CGI wrapper is now ready to rumble, and you just need to tell Hiawatha to use it by adding the following to the httpd.conf file:
WrapCGI = wrap_id
You can define multiple wrappers in cgi-wrapper.conf and then use them for different virtual hosts (see the "Virtual Hosts" box).
Virtual Hosts |
Like many other web servers, Hiawatha can serve up multiple, independent Internet sites. To allow this to happen, multiple (domain) names are first assigned to a physical server; this means that all browser requests are automatically directed to the same web server. The server analyzes the URL to determine the Internet site. The client sees multiple, additional virtual machine hosts. ISPs, in particular like this technique because it lets them serve multiple, smaller web presences with a single expensive IP address. To add virtual hosts to Hiawatha, you need to set up a separate section for each host in httpd.conf, as follows : VirtualHost { WebsiteRoot = /var/www/anothersite/wwwroot Hostname = www.myvirtualsite.com ... } Inside the brackets, you can use more or less any settings you used for the page itself (the default website in Hiawatha-speak). There are even a couple of functions that you can use only with virtual hosts, including four interesting Prevent security mechanisms. For example: PreventCMDI = yes stops command injection attacks by telling Hiawatha to convert backslashes, pipe symbols, and semicolons in the URL and POST data with underscores. Because this fairly rigorous approach also mangles uploaded binaries, it is disabled by default. The following line prevents cross-site request forgery (CSRF): PreventCSRF = yes The virtual host will then ignore any cookies sent to it by the browser if it reaches Hiawatha via an external link. The line PreventSQLi = yes combats SQL injection attacks by inserting a slash in front of each tick (`) in the URL, the POST data, and cookies. This feature works like Magic Quotes in PHP; also, you should not enable PreventSQLi if you use PHP scripts. Just like its sibling PreventCSRF, this function could mangle uploaded binaries. The last security function, PreventXSS = yes is designed to prevent cross-site scripting (XSS) attacks by replacing all the less than, greater than, quotes, and ticks in the URL with underscores. |
Typography
A final treat is UrlToolkit, which works similarly to the Apache server's mod_rewrite. Each URL the web server reads is compared with predefined patterns. In the case of a match, Hiawatha will perform a predefined action. Any regular expression can serve as a test pattern [2]. Listing 3 gives a small example.
Listing 3: Two Rule Sets with UrlToolkit |
01 UrlToolkit { 02 ToolkitID = varioustests 03 Match ^/php/ Return 04 Match /index.php4(.*) Rewrite /index.php$1 05 } 06 07 UrlToolkit { 08 ToolkitID = secret 09 Call varioustests 10 Match /secret(.*) DenyAccess 11 } |
Listing 3 looks far more cryptic than it actually is. The listing defines two rule sets. The ToolkitID for the upper rule set is varioustests, whereas I called the second one secret. The varioustests rule set first checks to see whether the URL starts with /php/. If this is the case, Hiawatha stops all further tests with this rule set (Return). If not, it checks to see whether the URL starts with index.php4. In this case, Hiawatha replaces the string with /index.php; that is, it drops the 4 in the file name.
The second rule set, secret, starts by calling its colleague varioustests (Call) and then refuses access to the /secret subdirectory. Table 1 gives an overview of possible actions.
After specifying rules in httpd.conf, you only need to tell the web server which rule set to use:
UseToolkit = secret
Listing 4 shows the complete Hiawatha configuration.
Listing 4: Complete Configuration (httpd.conf) |
01 #Basic configuration 02 Binding { 03 Port = 80 04 Interface = 192.168.2.123 05 } 06 07 Binding { 08 Port = 443 09 Interface = 129.168.2.123 10 UseSSL = yes 11 ServerKey = /usr/local/etc/hiawatha/serverkey.pem 12 } 13 14 WebsiteRoot = /usr/local/var/www/hiawatha 15 Hostname = localhost 16 17 #Logfiles 18 SystemLogfile = /usr/local/var/log/hiawatha/system.log 19 AccessLogfile = /usr/local/var/log/hiawatha/access.log 20 ErrorLogfile = /usr/local/var/log/hiawatha/error.log 21 GarbageLogfile = /usr/local/var/log/hiawatha/system.log 22 23 #Cache 24 CacheSize = 15 25 CacheMaxFilesize = 128 26 CacheMinFilesize = 256 27 28 #CGI 29 ExecuteCGI = yes 30 CGIextension = cgi 31 CGIhandler = /usr/bin/php5-cgi:php,php5 32 TimeForCGI = 5 33 #Nutze Wrapper: 34 WrapCGI = wrap_id 35 36 #Security functions 37 ServerId = www-data 38 ConnectionsTotal = 150 39 ConnectionsPerIP = 10 40 BanOnGarbage = 300 41 BanOnMaxReqSize = 60 42 BanOnFlooding = 10/1:35 43 BanOnCMDi = 60 44 BanOnSQLi = 70 45 BanlistMask = allow 192.168.2.111, deny 192.168.0.0/16 46 RebanDuringBan = yes 47 48 #UrlToolkit 49 UrlToolkit { 50 ToolkitID = varioustests 51 Match ^/php/ Return 52 Match /index.php4(.*) Rewrite /index.php$1 53 } 54 55 UrlToolkit { 56 ToolkitID = secret 57 Call varioustests 58 Match /secret(.*) DenyAccess 59 } 60 61 UseToolkit = secret |
Besides the security functions described in this article, Hiawatha has a number of other clever capabilities. For example, the web server has a more intelligent approach to Gzip compression than its colleagues, and it gives you the option of an internal error handler. If the client requests an XML file and the matching XSLT file exists, Hiawatha will automatically perform XSL transformation if needed. If the execution speed of CGI scripts is too slow, you can enable the FastCGI mechanism. Hiawatha also has a good understanding of access privileges for directories. You can even throttle the upload speed for specified file types.
If you would like to know more about Hiawatha, check the slightly terse HowTo [2]. The HowTo even discusses the option of combining the web server with AppArmor and Grsecurity [3].
INFO |
[1] Hiawatha web server : http://www.hiawatha-Webserver.org
[2] Hiawatha HowTo: http://www.hiawatha-Webserver.org/howto [3] Grsecurity: http://www.grsecurity.net |
THE AUTHOR |
Tim Schürmann is a computer scientist and is currently working as a freelance author. Tim starting working with Linux back in the 1990s and has published several books and articles in various languages on the free operating system. Apart from that, he is absolutely convinced that VI must have been invented by the devil himself. For more information, visit Tim's homepage at www.tim-schuermann.de. |