Tutorials

Server CGI HowTo

Supposed you are running a server, and want to execute unix shell scripts to produce web content to be displayed by a web browser. Then the method of choice is CGI, the Common Gateway Interface.

How CGI Works

The CGI scripts are regulare Unix shell scripts stored on the web server (usually in the cgi/bin directory of the web server’s html root directory) which get invoked by pointing an url at the script.

Then the response visible in the web browser is the output of the script to the standart output stream. This means that the output of the script is transferred by the http protocol from the server to the browser.

Example:

If you want to deliver the uptime as response of the server www.example.com, then you need to copy the following script under the file name “uptime” to the cgi/bin directory of the server and point your browser to www.example.com/cgi/bin/uptime:

#!/bin/bash

echo "Content-type: text/html"
echo ""

echo '<html>'
echo '<head>'
echo '<title>System Uptime</title>'
echo '</head>'
echo '<body>'

  PATH="/bin:/usr/bin"
  export $PATH

echo '<h3>'
  hostname
echo '</h3>'
  uptime

echo '</body>'
echo '</html>'

exit 0

The above shell script needs to be executable:

sudo chmod +x uptime

To see an example cgi run, navigate here:

A CGI example with forms:

#!/bin/bash

echo "Content-type: text/html"
echo ""

echo '<html>'
echo '<head>'
echo '<title>CGI Form Example</title>'
echo '</head>'
echo '<body>'

  PATH="/bin:/usr/bin"
  export $PATH

  # create a html get action for a form
  echo "<form method=GET action=\"${SCRIPT}\">"\
       '<table>'\
       '  <tr><td>Input</TD><TD><input type="text" name="VAL" size=30></td></tr>'\
       '</table>'\
       '<br><input type="submit" value="Submit Form"></form>'

  # make sure we have been invoked properly
  if [ "$REQUEST_METHOD" != "GET" ]; then
     echo "<hr>script error: cannot complete request<hr>"
     exit 1
  fi

  # if no search arguments, exit gracefully
  if [ -z "$QUERY_STRING" ]; then
     exit 0
  else
     # extract the submitted data we are looking for with sed
     VAL=`echo "$QUERY_STRING" | sed -n 's/^.*VAL=\([^&]*\).*$/\1/p' | sed "s/%20/ /g"`

     # display the extracted value below the form
     echo "Value: $VAL"
  fi

echo '</body>'
echo '</html>'

exit 0

The above form contains a single text field. When a user enters string value in that field, the value end up in the VAL shell variable. For this simple demo, we just display the value below the form.

To see an example cgi run, navigate here:

CGI Security

To avoid cross site scripting, the apache server replaces all meta-characters in the query response string with a hex-code. For example the back-tick “`” is replaced with “%60″. If that was not the case, a fatal exploit is easily constructed:

Consider an input value of “`rm -rf *`” that gets assigned to a variable V in the shell script. When we have a command like ‘echo $$$V’ the “rm” shell command would end up being executed instead of being echoed to the output stream. That would be fatal. So all variables in a shell script need to be quoted for safety reasons like this: ‘echo "$$$V"

As a general rule of thumb, we need to be careful about filtering the input to avoid cross site scripting.

This means that all meta-characters need to be stripped off the input. Or better the other way round: Just do not strip characters that are part of a valid input. For example for an email address as input, one needs to filter all characters but a-z, A-Z, 0-9 and .@_- :

VAL="${VAL/\%40/@}" # undo replacement of @ with %40
VAL=`echo "$VAL" | sed "s/[^a-zA-Z0-9.@_\-]//g"` # remove all meta characters for safety

Options: