Notes for HTTP Service, Apache and CGI

  1. On our systems, the following commands will install Apache (or httpd: the HyperText Transfer Protocol Daemon):
    mount -wo remount /
    cd /usr/src
    tar -xjf httpd-2.2.2.tar.bz2
    cd httpd-2.2.2
    
    groupadd -g 25 apache
    useradd -c "Apache Server" -d /dev/null -g apache -s /bin/false -u 25 apache
    
    (patch -Np1 -i ../httpd-2.2.2-config-1.patch) 2>&1 | tee -a ../apache.out
    
    (./configure --enable-layout=FHS --enable-mods-shared=all --with-expat=/usr --enable-ssl --with-pcre --with-z) 2>&1 | tee -a ../apache.out
    
    (make) 2>&1 | tee -a ../apache.out
    
    (make install) 2>&1 | tee -a ../apache.out
    
    chown -v root:root /usr/lib/apache/httpd.exp \
        /usr/sbin/{apxs,apachectl,dbmmanage,envvars{,-std}} \
        /usr/share/man/man1/{dbmmanage,ht{dbm,digest,passwd}}.1 \
        /usr/share/man/man8/{ab,apachectl,apxs,htcacheclean,httpd}.8 \
        /usr/share/man/man8/{logresolve,rotatelogs,suexec}.8 &&
    chown -v -R apache:apache /srv/www
    
    sed -i -e "s/User daemon/User apache/" -e "s/Group daemon/Group apache/" /etc/apache/httpd.conf
    
    cd /sources/blfs-bootscripts-20060910/
    make install-apache
    cd
    
    mount -ro remount /
    

    The patch makes a small change in the configuration parameters.

    This configuration is based on Beyond Linux From Scratch 6.2, and causes Apache to run its slave processes under the unprivileged user "apache". The "expat", "ssl", "pcre" and "z" parameters to configure tells Apache to use the versions which are already installed. The file /etc/rc.d/init.d/apache is the script used to start and stop Apache.
  2. configuration file /etc/apache/httpd.conf

  3. CGI - Common Gateway Interface

    Sample CGI script, which illustrates the data provided for either GET or POST requests:

    #!/bin/sh
    
    echo Content-type: text/plain
    echo 
    echo Server name is "$SERVER_NAME"
    echo Server is listening on port "$SERVER_PORT"
    echo Request method was "$REQUEST_METHOD"
    echo Query string is "$QUERY_STRING"
    echo Client IP address is "$REMOTE_ADDR"
    echo Content type is "$CONTENT_TYPE"
    echo Content length is "$CONTENT_LENGTH"
    echo Client will accept the MIME types "$HTTP_ACCEPT"
    echo Client Browser is "$HTTP_USER_AGENT"
    echo 
    echo stdin follows:
    read l
    while [ -n "$l" ]; do
        echo $l
        read l
    done
    echo end of stdin
    echo 
    
    A CGI script for a calculator, which generates HTML; note the translation of escaped characters back into their original form for input into BASH:
    #!/bin/sh
    
    echo Content-type: text/html
    echo 
    echo '<html>'
    echo '<body bgcolor="#E0FFFF">'
    echo '<h3>'
    echo "Hi $REMOTE_ADDR, welcome to the calculator at $SERVER_NAME!"
    echo '</h3><p>'
    echo '<h2>'
    if [ $REQUEST_METHOD = GET ]; then
        text=$(echo $QUERY_STRING | sed -e 's/^.*text=//')
    else
        read l
        text=$(echo $l | sed -e 's/^.*text=//')
    fi
    trtext=$(echo $text | 
        sed -e 's/%2B/+/g' | 
        sed -e 's^%2F^/^g' | 
        sed -e 's/%26/\&/g' | 
        sed -e 's/%7C/|/g' | 
        sed -e 's/%21/!/g' | 
        sed -e 's/%7E/~/g' | 
        sed -e 's/%5E/^/g' | 
        sed -e 's/%28/(/g' | 
        sed -e 's^%29^)^g' | 
        sed -e 's/%25/%/g' | 
        sed -e 's/%3C/</g' | 
        sed -e 's/%3E/>/g')
    result=$(echo $[$trtext])
    if [ $? -ne 0 ]; then
        echo "Syntax error in expression $trtext"
    else
        echo "$trtext = $result"
    fi
    echo '</h2>'
    echo '</body>'
    echo '</html>'
    echo 
    
  4. Sample forms for GET and POST

  5. EXERCISES for HTTP Service, Apache and CGI:

    1. Start Apache using the command /etc/rc.d/init.d/apache start. Observe from ps aux output that the actual server program is httpd. Note that the master process runs as root; it directs client requests to the slave processes. Test Apache by entering "127.0.0.1" as the URL in mozilla.
    2. The document root for your server is /srv/www/htdocs. Create a home page for your server to replace the current index.html file. Reload the URL 127.0.0.1 to test your new home page.
    3. Using the information in the week 10 notes, add a firewall rule to permit access to your web server from other PCs in the lab. Re-run your firewall script and test access to your server from other stations.
    4. Stop Apache using the command /etc/rc.d/init.d/apache stop. Examine the files in /var/log/apache.

      The access_log file contains the following information for every file served to a client:

      • the client IP address
      • the date and time of the request
      • the method (typically GET or POST)
      • the file name requested by the client
      • the HTTP version used by the client
      • the result code for the request
      • the number of bytes in the file
    5. Configure Apache to only serve to the PCs on your island, and to the instructor (192.168.1.150). Do not use firewall rules to do this.
    6. First change the name of the file "index.html" to "home.html".

      Then turn off FollowSymLinks and Indexes for all directories. This is a non-trivial exercise because on our systems, /srv is a symbolic link! (Hint: try using its real name.)

    7. Create a form which asks the client for their first name (use name=firstname in the input tag). The page displaying the form should be called "welcome.html". Write a short CGI script to send them an HTML page welcoming them by name to your system. Use both the GET and POST methods, calling the scripts get.cgi and post.cgi, respectively.
    8. Capture HTTP GET and POST packets from a variety of browser platforms, using the maximum query string length you wish to accept. The packet sizes will very; find which platform sends the largest packet and record that length.
      In practice, this needs to be done for the largest request that can be made of your server. This will be determined by both the longest possible URL and the largest possible query.
      Suppose that length is 700 bytes. Subtracting the length of the ethernet header, a firewall rule to drop excessive packets would look like this:
      iptables -A INPUT -i eth0 -p tcp --dport 80 -m length --length 687:65535 -j DROP
      Implement such a firewall rule and test it, first sending a legitimate request, and then increasing the size of the request by manually typing additional query string characters on the end of the original query string. Use iptables -L -v to examine the dropped packet and bytes counts associated with your request.

      What are the logistical difficulties in implementing such a rule on an enterprise server?


©2012, Kenneth R. Koehler. All Rights Reserved. This document may be freely reproduced provided that this copyright notice is included.

Please send comments or suggestions to the author.