1) Customize Pages with CGI
CGI can show different pages to different users depending on user
preferences.
Exercise:
1.1 Create a form that asks a user to input their name into a
textfield and to choose a color from a selection of radio buttons.
Create a CGI script that displays a page with a
short message (e.g. "Thank you", name, "for your request") in the color
which the user chose.
2) Environment Variables
#!/usr/bin/env python
#
######### CGI header #######################################
import cgi
print "Content-Type: text/html\n"
form = cgi.FieldStorage()
######### import the operating system module ###############
import os
########## HTML header ######################################
print """
<html>
<head> <title>Environment Variables
</title> </head>
<body>
<h2>Here are all the environment variables:</h2>
"""
############ print the environment variables ########
keys = os.environ.keys()
keys.sort()
for item in keys:
print item, ": ", os.environ[item], "<br>"
########## HTML footer ######################################
print """
</body></html>
"""
Exercises
2.1 Insert the code for printing environment variables into
your CGI script from the previous exercise. In the HTML
form first set the form method to GET, then to POST. You'll
notice that some environment variables, such as CONTENT_LENGTH
are only available for one of the two methods.
2.2 You can use CONTENT_LENGTH to increase the security of your
CGI script (by ensuring that the user is not attempting to overload
your script with large amounts of data). Insert an if statement
into your script that prints a warning if
os.environ["REQUEST_METHOD"] is set to POST and
int(os.environ["CONTENT_LENGTH"]) is larger than 10.
(Note: int() is used to convert the string value of the
environment variable into a number. The value 10 is too
small for most scripts. If you are going to use this in your
project, you need to adjust the value.)
3) Security on CGI Pages
Because CGI scripts run on a server that is accessed by remote clients,
there are security risks for the server!
Here are some security tips:
a) General tips
- Don't install CGI code from untrusted sources on your server.
- Using cookie data involves the same security risks as using
form data.
- If you have several forms and CGI scripts that communicate among
each other, each script requires the same security checks.
It is not sufficient to only make the first script secure.
- It is always a good idea to
check the CONTENT-LENGTH variable to restrict amount of
data that a script accepts from a form.
- A fairly rigid security measure is to use
HTTP_REFERER to restrict the forms that can access your CGI script.
But this is not usually a good idea because users sometimes want
to link to a page that is dynamically created by a CGI script.
Furthermore, hackers can manipulate the HTTP_REFERER variable.
b) Check user input!
- For input from radio buttons, menu selections, check boxes,
check all possible values with an if statement. In case of unexpected
values, print an error message and discontinue with the script.
To terminate the script use
import sys
sys.exit()
- For input from text areas, check for unusual characters and
check the length of the input (either using CONTENT_LENGTH for
all input or using len() for each text area).
- Before printing any user input, HTML tags need to be removed.
Insert the following piece of code after the line with
form = cgi.FieldStorage()
############### this replaces <> with HTML meta characters ######
import re
open_tag = re.compile(r"<")
close_tag = re.compile(r">")
for item in form.keys():
form[item].value =
open_tag.sub ("<", form[item].value)
form[item].value =
close_tag.sub (">", form[item].value)
c) File handling
- Don't ask the user for a filename and then write to that file.
- Files that are written to should not be in a directory
that allows server-side includes, active server pages, PHP
pages, or other HTML template systems.
- If your script writes to a file, lock the file so that two
scripts cannot write to it at the same time.
d) System calls (Using the os module)
- Never pass user input to a system() or exec() call
or any other function in the os module.
- For example, don't write a script that asks a user to enter
the name of an environment variable and then prints the value
of that variable.
- If you use sendmail to send
email to a user, apply something like
email_check = re.compile(r"^[\w\.+-]+\@[\w\.+-]+$")
result = email_check.search(email)
if not result:
print "Wrong email address"
sys.exit()
to the address and use "sendmail -t -oi"
e) Passwords
- All passwords are completely insecure unless the whole connection
is encrypted using a secure channel.
- Don't use knowledge of a parameter name as a security mechanism
(eg. a "secret" parameter such as
xyssx=true). This was the cause of the Hotmail security
problem!
More information on security is available from
this W3C
page. Even though the CGI examples in section 6 of that page
refer to Perl, the security problems for Python are similar.
Exercise
3.1 Apply all the security measures mentioned above under
"b) Check user input" to your script from exercise 1.1.
For example, check that neither name nor color are empty,
check that the color is one of the radio button choices from your form,
check that name contains only word characters, space
or hyphen (-), and
check that the name is not longer than 50 chars.
If your script encounters any security problem, print
an error message and exit the script using sys.exit().